diff --git a/.gitattributes b/.gitattributes
index 32c2d98082edf9f1cdd2350c0ca20bf7d9068614..dbd5d606b6ebb976870b3d223276d83687df3b29 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -46,3 +46,12 @@ Yunzai/plugins/miao-plugin/resources/common/font/NZBZ.ttf filter=lfs diff=lfs me
Yunzai/plugins/miao-plugin/resources/help/icon.png filter=lfs diff=lfs merge=lfs -text
Yunzai/plugins/miao-plugin/resources/meta/character/莱欧斯利/imgs/splash.webp filter=lfs diff=lfs merge=lfs -text
Yunzai/plugins/Guoba-Plugin/server/static/assets/HYWH-65W.woff filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/TRSS-Plugin/Picture/苏半夏.png filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/TRSS-Plugin/Picture/苏半夏D.png filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/admin/imgs/bg/default.jpg filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/common/font/FZB.ttf filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/common/font/FZB.woff filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/common/font/HYWH-65W.ttf filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/common/font/HYWH-65W.woff filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/common/font/NZBZ.ttf filter=lfs diff=lfs merge=lfs -text
+Yunzai/plugins/yenai-plugin/resources/help/imgs/default.png filter=lfs diff=lfs merge=lfs -text
diff --git a/Yunzai/plugins/TRSS-Plugin/.gitignore b/Yunzai/plugins/TRSS-Plugin/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4c354429091b3253e4502a5f4da8a8f5e9bcb3d5
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+Real-ESRGAN
+RemBG
+GenshinVoice
+ChatWaifu
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/AliyunPan.js b/Yunzai/plugins/TRSS-Plugin/Apps/AliyunPan.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cc9ed1e6060da96fd416b6fe4d6477e1461ee83
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/AliyunPan.js
@@ -0,0 +1,215 @@
+const Commands = {
+ "": "help",
+ "帮助": "help",
+ "相簿": "album",
+ "下载": "download",
+ "链接": "locate",
+ "查看": "ls",
+ "创建目录": "mkdir",
+ "移动": "mv",
+ "回收站": "recycle",
+ "重命名": "rename",
+ "删除": "rm",
+ "分享": "share",
+ "同步备份": "sync",
+ "树形图": "tree",
+ "上传": "upload",
+ "在线网盘": "webdav",
+ "切换网盘": "drive",
+ "登录账号": "login",
+ "账号列表": "loglist",
+ "退出账号": "logout",
+ "空间配额": "quota",
+ "切换账号": "su",
+ "当前账号": "who"
+}
+
+let path
+if (process.platform == "win32")
+ path = `${process.env.HOME}\\aliyunpan\\`
+else
+ path = `${process.env.HOME}/aliyunpan/`
+const cmdPath = `${path}aliyunpan`
+const errorTips = "请使用脚本安装阿里云盘,并正常登录后再使用此功能\nhttps://Yunzai.TRSS.me\nhttps://TRSS.me"
+let Running
+let es
+
+export class AliyunPan extends plugin {
+ constructor() {
+ super({
+ name: "阿里云盘",
+ dsc: "阿里云盘",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^阿里云盘上传",
+ fnc: "UploadDetect"
+ },
+ {
+ reg: "^阿里云盘下载",
+ fnc: "Download"
+ },
+ {
+ reg: "^阿里云盘",
+ fnc: "AliyunPan"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async execTask(e, cmd) {
+ logger.mark(`[阿里云盘] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[阿里云盘]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.stdout) {
+ await this.reply(ret.stdout.trim(), true)
+ }
+
+ if (ret.stderr) {
+ await this.reply(`标准错误输出:\n${ret.stderr.trim()}`, true)
+ }
+
+ if (ret.error) {
+ logger.error(`阿里云盘错误:${logger.red(ret.error)}`)
+ await this.reply(`阿里云盘错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+ }
+
+ async UploadDetect(e) {
+ es = this.e
+ this.setContext("Upload")
+ await this.reply("请发送文件", true)
+ }
+
+ async Upload(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if(!this.e.file)return false
+
+ this.finish("Upload")
+ const filePath = `${path}${this.e.file.name}`
+ let fileUrl
+ if (this.e.file.url)
+ fileUrl = this.e.file.url
+ else if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(this.e.file.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(this.e.file.fid)
+ this.e = es
+
+ if (!fileUrl) {
+ await this.reply("文件链接获取失败", true)
+ return false
+ }
+
+ if (Running) {
+ await this.reply("有正在执行的阿里云盘任务,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply(`开始下载文件,请稍等……\n文件链接:${fileUrl}\n保存路径:${filePath}`, true)
+
+ const ret = await common.downFile(fileUrl, filePath)
+ if (!ret) {
+ await this.reply("文件下载错误", true)
+ Running = false
+ return true
+ }
+
+ const remotePath = this.e.msg.replace("阿里云盘上传", "").trim()
+ await this.reply(`文件下载完成,开始上传到:${remotePath}`, true)
+ const cmd = `'${cmdPath}' upload '${filePath}' '${remotePath}'`
+
+ await this.execTask(es, cmd)
+ await fs.unlinkSync(filePath)
+ Running = false
+ }
+
+ async Download(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if (Running) {
+ await this.reply("有正在执行的阿里云盘任务,请稍等……", true)
+ return false
+ }
+
+ this.finish("Download")
+ const remotePath = this.e.msg.replace("阿里云盘下载", "").trim()
+ if (!remotePath) {
+ this.setContext("Download")
+ await this.reply("请发送文件路径", true)
+ return true
+ }
+
+ Running = true
+ await this.reply("开始下载文件,请稍等……", true)
+
+ const cmd = `'${cmdPath}' download '${remotePath}' --saveto '${path}'`
+
+ await this.execTask(e, cmd)
+
+ const filePath = `${path}${remotePath}`
+ if (!fs.existsSync(filePath)) {
+ await this.reply("文件下载错误", true)
+ Running = false
+ return true
+ }
+ if (!fs.statSync(filePath).isFile()) {
+ await this.reply("暂不支持发送文件夹", true)
+ Running = false
+ return true
+ }
+
+ try {
+ let res
+ if (this.e.isGroup) {
+ if (this.e.group.sendFile)
+ res = await this.e.group.sendFile(filePath)
+ else
+ res = await this.e.group.fs.upload(filePath)
+ } else {
+ res = await this.e.friend.sendFile(filePath)
+ }
+
+ if (res) {
+ let fileUrl
+ if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(res.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(res)
+
+ if (fileUrl)
+ await this.reply(`文件发送完成:${fileUrl}`, true)
+ else
+ await this.reply(`文件发送完成:${JSON.stringify(res)}`, true)
+ }
+
+ } catch(err) {
+ logger.error(`文件发送错误:${logger.red(JSON.stringify(err))}`)
+ await this.reply(`文件发送错误:${JSON.stringify(err)}`)
+ }
+
+ await fs.unlinkSync(filePath)
+ Running = false
+ }
+
+ async AliyunPan(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ let msg = this.e.msg.replace("阿里云盘", "").trim().split(" ")
+ if (msg[0] in Commands) {
+ msg[0] = Commands[msg[0]]
+ }
+ msg = msg.join(" ")
+ const cmd = `'${cmdPath}' ${msg}`
+ await this.execTask(e, cmd)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/BaiduPan.js b/Yunzai/plugins/TRSS-Plugin/Apps/BaiduPan.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a1a085f3c5a33df7bac69f7726f0bacd168875c
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/BaiduPan.js
@@ -0,0 +1,215 @@
+const Commands = {
+ "": "help",
+ "帮助": "help",
+ "复制": "cp",
+ "下载": "download",
+ "链接": "locate",
+ "查看": "ls",
+ "元信息": "meta",
+ "创建目录": "mkdir",
+ "移动": "mv",
+ "离线下载": "od",
+ "空间配额": "quota",
+ "回收站": "recycle",
+ "删除": "rm",
+ "搜索": "search",
+ "分享": "share",
+ "转存": "transfer",
+ "树形图": "tree",
+ "上传": "upload",
+ "登录账号": "login",
+ "账号列表": "loglist",
+ "退出账号": "logout",
+ "切换账号": "su",
+ "当前账号": "who"
+}
+
+let path
+if (process.platform == "win32")
+ path = `${process.env.HOME}\\BaiduPCS-Go\\`
+else
+ path = `${process.env.HOME}/BaiduPCS-Go/`
+const cmdPath = `${path}BaiduPCS-Go`
+const errorTips = "请使用脚本安装百度网盘,并正常登录后再使用此功能\nhttps://Yunzai.TRSS.me\nhttps://TRSS.me"
+let Running
+let es
+
+export class BaiduPan extends plugin {
+ constructor() {
+ super({
+ name: "百度网盘",
+ dsc: "百度网盘",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^百度网盘上传",
+ fnc: "UploadDetect"
+ },
+ {
+ reg: "^百度网盘下载",
+ fnc: "Download"
+ },
+ {
+ reg: "^百度网盘",
+ fnc: "BaiduPan"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async execTask(e, cmd) {
+ logger.mark(`[百度网盘] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[百度网盘]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.stdout) {
+ await this.reply(ret.stdout.trim(), true)
+ }
+
+ if (ret.stderr) {
+ await this.reply(`标准错误输出:\n${ret.stderr.trim()}`, true)
+ }
+
+ if (ret.error) {
+ logger.error(`百度网盘错误:${logger.red(ret.error)}`)
+ await this.reply(`百度网盘错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+ }
+
+ async UploadDetect(e) {
+ es = this.e
+ this.setContext("Upload")
+ await this.reply("请发送文件", true)
+ }
+
+ async Upload(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if(!this.e.file)return false
+
+ this.finish("Upload")
+ const filePath = `${path}${this.e.file.name}`
+ let fileUrl
+ if (this.e.file.url)
+ fileUrl = this.e.file.url
+ else if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(this.e.file.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(this.e.file.fid)
+ this.e = es
+
+ if (!fileUrl) {
+ await this.reply("文件链接获取失败", true)
+ return false
+ }
+
+ if (Running) {
+ await this.reply("有正在执行的百度网盘任务,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply(`开始下载文件,请稍等……\n文件链接:${fileUrl}\n保存路径:${filePath}`, true)
+
+ const ret = await common.downFile(fileUrl, filePath)
+ if (!ret) {
+ await this.reply("文件下载错误", true)
+ Running = false
+ return true
+ }
+
+ const remotePath = this.e.msg.replace("百度网盘上传", "").trim()
+ await this.reply(`文件下载完成,开始上传到:${remotePath}`, true)
+ const cmd = `'${cmdPath}' upload '${filePath}' '${remotePath}'`
+
+ await this.execTask(es, cmd)
+ await fs.unlinkSync(filePath)
+ Running = false
+ }
+
+ async Download(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if (Running) {
+ await this.reply("有正在执行的百度网盘任务,请稍等……", true)
+ return false
+ }
+
+ this.finish("Download")
+ const remotePath = this.e.msg.replace("百度网盘下载", "").trim()
+ if (!remotePath) {
+ this.setContext("Download")
+ await this.reply("请发送文件路径", true)
+ return true
+ }
+
+ Running = true
+ await this.reply("开始下载文件,请稍等……", true)
+
+ const cmd = `'${cmdPath}' download '${remotePath}' --saveto '${path}'`
+
+ await this.execTask(e, cmd)
+
+ const filePath = `${path}${remotePath.substr(remotePath.lastIndexOf("/")+1)}`
+ if (!fs.existsSync(filePath)) {
+ await this.reply("文件下载错误", true)
+ Running = false
+ return true
+ }
+ if (!fs.statSync(filePath).isFile()) {
+ await this.reply("暂不支持发送文件夹", true)
+ Running = false
+ return true
+ }
+
+ try {
+ let res
+ if (this.e.isGroup) {
+ if (this.e.group.sendFile)
+ res = await this.e.group.sendFile(filePath)
+ else
+ res = await this.e.group.fs.upload(filePath)
+ } else {
+ res = await this.e.friend.sendFile(filePath)
+ }
+
+ if (res) {
+ let fileUrl
+ if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(res.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(res)
+
+ if (fileUrl)
+ await this.reply(`文件发送完成:${fileUrl}`, true)
+ else
+ await this.reply(`文件发送完成:${JSON.stringify(res)}`, true)
+ }
+
+ } catch(err) {
+ logger.error(`文件发送错误:${logger.red(JSON.stringify(err))}`)
+ await this.reply(`文件发送错误:${JSON.stringify(err)}`)
+ }
+
+ await fs.unlinkSync(filePath)
+ Running = false
+ }
+
+ async BaiduPan(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ let msg = this.e.msg.replace("百度网盘", "").trim().split(" ")
+ if (msg[0] in Commands) {
+ msg[0] = Commands[msg[0]]
+ }
+ msg = msg.join(" ")
+ const cmd = `'${cmdPath}' ${msg}`
+ await this.execTask(e, cmd)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/File.js b/Yunzai/plugins/TRSS-Plugin/Apps/File.js
new file mode 100644
index 0000000000000000000000000000000000000000..f28fce2ba76f44bb44a22d6f2e85b4215ee55f01
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/File.js
@@ -0,0 +1,150 @@
+let Running
+let es
+
+export class File extends plugin {
+ constructor() {
+ super({
+ name: "文件操作",
+ dsc: "文件操作",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^文件查看",
+ fnc: "List"
+ },
+ {
+ reg: "^文件上传",
+ fnc: "Upload"
+ },
+ {
+ reg: "^文件下载",
+ fnc: "DownloadDetect"
+ }
+ ]
+ })
+ }
+
+ async List(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+
+ this.finish("List")
+ const filePath = this.e.msg.replace("文件查看", "").trim()
+ if (!filePath) {
+ this.setContext("List")
+ await this.reply("请发送文件路径", true)
+ return true
+ }
+
+ if (!fs.existsSync(filePath)) {
+ await this.reply("路径不存在", true)
+ return true
+ }
+ if (!fs.statSync(filePath).isDirectory()) {
+ await this.reply("该路径不是一个文件夹", true)
+ return true
+ }
+
+ await this.reply(fs.readdirSync(filePath).join("\n"), true)
+ }
+
+ async Upload(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if (Running) {
+ await this.reply("有正在执行的文件任务,请稍等……", true)
+ return false
+ }
+
+ this.finish("Upload")
+ const filePath = this.e.msg.replace("文件上传", "").trim()
+ if (!filePath) {
+ this.setContext("Upload")
+ await this.reply("请发送文件路径", true)
+ return true
+ }
+
+ if (!fs.existsSync(filePath)) {
+ await this.reply("文件不存在", true)
+ return true
+ }
+ if (!fs.statSync(filePath).isFile()) {
+ await this.reply("暂不支持上传文件夹", true)
+ return true
+ }
+
+ Running = true
+ await this.reply("开始上传文件,请稍等……", true)
+
+ try {
+ let res
+ if (this.e.isGroup) {
+ if (this.e.group.sendFile)
+ res = await this.e.group.sendFile(filePath)
+ else
+ res = await this.e.group.fs.upload(filePath)
+ } else {
+ res = await this.e.friend.sendFile(filePath)
+ }
+
+ if (res) {
+ let fileUrl
+ if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(res.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(res)
+
+ if (fileUrl)
+ await this.reply(`文件上传完成:${fileUrl}`, true)
+ else
+ await this.reply(`文件上传完成:${JSON.stringify(res)}`, true)
+ }
+
+ } catch(err) {
+ logger.error(`文件上传错误:${logger.red(JSON.stringify(err))}`)
+ await this.reply(`文件上传错误:${JSON.stringify(err)}`)
+ }
+ Running = false
+ }
+
+ async DownloadDetect(e) {
+ es = this.e
+ this.setContext("Download")
+ await this.reply("请发送文件", true)
+ }
+
+ async Download(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ if(!this.e.file)return false
+
+ this.finish("Download")
+ const filePath = `${es.msg.replace("文件下载", "").trim()||process.cwd()}/${this.e.file.name}`
+ let fileUrl
+ if (this.e.file.url)
+ fileUrl = this.e.file.url
+ else if (this.e.group?.getFileUrl)
+ fileUrl = await this.e.group.getFileUrl(this.e.file.fid)
+ else if (this.e.friend?.getFileUrl)
+ fileUrl = await this.e.friend.getFileUrl(this.e.file.fid)
+ this.e = es
+
+ if (!fileUrl) {
+ await this.reply("文件链接获取失败", true)
+ return false
+ }
+
+ if (Running) {
+ await this.reply("有正在执行的文件任务,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply(`开始下载文件,请稍等……\n文件链接:${fileUrl}\n保存路径:${filePath}`, true)
+
+ const ret = await common.downFile(fileUrl, filePath)
+ if (ret) {
+ await this.reply("文件下载完成", true)
+ } else {
+ await this.reply("文件下载错误", true)
+ }
+ Running = false
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/Markdown.js b/Yunzai/plugins/TRSS-Plugin/Apps/Markdown.js
new file mode 100644
index 0000000000000000000000000000000000000000..0479d38c19d8ed903e3a8dceb7314d9e26987c57
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/Markdown.js
@@ -0,0 +1,45 @@
+const htmlDir = `${process.cwd()}/plugins/TRSS-Plugin/Resources/Markdown/`
+const tplFile = `${htmlDir}Markdown.html`
+
+export class Markdown extends plugin {
+ constructor() {
+ super({
+ name: "Markdown",
+ dsc: "Markdown",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^md.+",
+ fnc: "Markdown"
+ }
+ ]
+ })
+ }
+
+ async Markdown(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const msg = this.e.msg.replace("md", "").trim()
+ logger.mark(`[Markdown] 查看:${logger.blue(msg)}`)
+
+ let mdFile = msg
+ if (/^https?:\/\//.test(msg)) {
+ mdFile =`${process.cwd()}/data/cache.md`
+ const ret = await common.downFile(msg, mdFile)
+ if (!ret) {
+ await this.reply("文件下载错误", true)
+ return false
+ }
+ }
+
+ if (!(fs.existsSync(mdFile) && fs.statSync(mdFile).isFile())) {
+ await this.reply("文件不存在", true)
+ return false
+ }
+
+ const Markdown = md.render(fs.readFileSync(mdFile, "utf-8"))
+ const img = await puppeteer.screenshot("Markdown", { tplFile, htmlDir, Markdown })
+
+ await this.reply(img, true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/QRCode.js b/Yunzai/plugins/TRSS-Plugin/Apps/QRCode.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e09e376d18d9a8650c3dcb66ecd09b15808c07d
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/QRCode.js
@@ -0,0 +1,23 @@
+export class QRCode extends plugin {
+ constructor() {
+ super({
+ name: "二维码生成",
+ dsc: "二维码生成",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^二维码.+",
+ fnc: "QRCode"
+ }
+ ]
+ })
+ }
+
+ async QRCode(e) {
+ const msg = this.e.msg.replace("二维码", "").trim()
+ logger.mark(`[二维码生成] 信息:${logger.blue(msg)}`)
+ const img = (await QR.toDataURL(msg)).replace("data:image/png;base64,", "base64://")
+ await this.reply(segment.image(img), true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/RealESRGAN.js b/Yunzai/plugins/TRSS-Plugin/Apps/RealESRGAN.js
new file mode 100644
index 0000000000000000000000000000000000000000..2192136168235b24b726073be272f44a66a46c20
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/RealESRGAN.js
@@ -0,0 +1,106 @@
+const path = `${process.cwd()}/plugins/TRSS-Plugin/Real-ESRGAN/`
+const errorTips = "请查看安装使用教程:\nhttps://Yunzai.TRSS.me\n并将报错通过联系方式反馈给开发者"
+let model
+let Running
+
+export class RealESRGAN extends plugin {
+ constructor() {
+ super({
+ name: "图片修复",
+ dsc: "图片修复",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^#?(动漫)?图片修复$",
+ fnc: "DetectImage"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async DetectImage(e) {
+ if (this.e.msg.match("动漫")) {
+ model = "RealESRGAN_x4plus_anime_6B"
+ } else {
+ model = "RealESRGAN_x4plus"
+ }
+
+ let reply
+ if (this.e.getReply) {
+ reply = await this.e.getReply()
+ } else if (this.e.source) {
+ if (this.e.group?.getChatHistory)
+ reply = (await this.e.group.getChatHistory(this.e.source.seq, 1)).pop()
+ else if (this.e.friend?.getChatHistory)
+ reply = (await this.e.friend.getChatHistory(this.e.source.time, 1)).pop()
+ }
+ if (reply?.message) for (const i of reply.message)
+ if (i.type == "image" || i.type == "file") {
+ this.e.img = [i.url]
+ break
+ }
+
+ if (!this.e.img) {
+ this.setContext("RealESRGAN")
+ await this.reply("请发送图片", true)
+ } else {
+ this.RealESRGAN()
+ }
+ }
+
+ async RealESRGAN(e) {
+ if (!this.e.img) {
+ return false
+ }
+
+ this.finish("RealESRGAN")
+ if (Running) {
+ await this.reply("正在生成,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply("开始生成,请稍等……", true)
+
+ let url
+ if (config.RealESRGAN.api) {
+ url = `${config.RealESRGAN.api}?user_id=${this.e.user_id}&bot_id=${this.e.self_id}&fp32=True&tile=100&model_name=${model}&input=${encodeURIComponent(this.e.img[0])}`
+ } else {
+ let ret = await common.downFile(this.e.img[0], `${path}input.${config.RealESRGAN.format}`)
+ if (!ret) {
+ await this.reply("下载图片错误", true)
+ await this.reply(errorTips)
+ Running = false
+ return true
+ }
+
+ logger.mark(`[图片修复] 图片保存成功:${logger.blue(this.e.img[0])}`)
+
+ const cmd = `bash '${path}main.sh' --fp32 --tile 100 -n ${model} -i input.${config.RealESRGAN.format}`
+
+ logger.mark(`[图片修复] 执行:${logger.blue(cmd)}`)
+ ret = await this.execSync(cmd)
+ logger.mark(`[图片修复]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`图片修复错误:${logger.red(ret.error)}`)
+ await this.reply(`图片修复错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+
+ url = `file://${path}results/input_out.${config.RealESRGAN.format}`
+ }
+
+ logger.mark(`[图片修复] 发送图片:${logger.blue(url)}`)
+ Running = false
+ await this.reply(segment.image(url), true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/RemBG.js b/Yunzai/plugins/TRSS-Plugin/Apps/RemBG.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d9ded60405a72074f25837dd505baa206e6aef9
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/RemBG.js
@@ -0,0 +1,106 @@
+const path = `${process.cwd()}/plugins/TRSS-Plugin/RemBG/`
+const errorTips = "请查看安装使用教程:\nhttps://Yunzai.TRSS.me\n并将报错通过联系方式反馈给开发者"
+let model
+let Running
+
+export class RemBG extends plugin {
+ constructor() {
+ super({
+ name: "图片背景去除",
+ dsc: "图片背景去除",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^#?(动漫)?(图片)?(去除?背景|背景去除?)$",
+ fnc: "DetectImage"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async DetectImage(e) {
+ if (this.e.msg.match("动漫")) {
+ model = "anime.sh"
+ } else {
+ model = "main.sh i"
+ }
+
+ let reply
+ if (this.e.getReply) {
+ reply = await this.e.getReply()
+ } else if (this.e.source) {
+ if (this.e.group?.getChatHistory)
+ reply = (await this.e.group.getChatHistory(this.e.source.seq, 1)).pop()
+ else if (this.e.friend?.getChatHistory)
+ reply = (await this.e.friend.getChatHistory(this.e.source.time, 1)).pop()
+ }
+ if (reply?.message) for (const i of reply.message)
+ if (i.type == "image" || i.type == "file") {
+ this.e.img = [i.url]
+ break
+ }
+
+ if (!this.e.img) {
+ this.setContext("RemBG")
+ await this.reply("请发送图片", true)
+ } else {
+ this.RemBG()
+ }
+ }
+
+ async RemBG(e) {
+ if (!this.e.img) {
+ return false
+ }
+
+ this.finish("RemBG")
+ if (Running) {
+ await this.reply("正在生成,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply("开始生成,请稍等……", true)
+
+ let url
+ if (config.RemBG.api) {
+ url = `${config.RemBG.api}?user_id=${this.e.user_id}&bot_id=${this.e.self_id}&url=${encodeURIComponent(this.e.img[0])}`
+ } else {
+ let ret = await common.downFile(this.e.img[0], `${path}input.png`)
+ if (!ret) {
+ await this.reply("下载图片错误", true)
+ await this.reply(errorTips)
+ Running = false
+ return true
+ }
+
+ logger.mark(`[图片背景去除] 图片保存成功:${logger.blue(this.e.img[0])}`)
+
+ const cmd = `bash '${path}'${model} input.png output.png`
+
+ logger.mark(`[图片背景去除] 执行:${logger.blue(cmd)}`)
+ ret = await this.execSync(cmd)
+ logger.mark(`[图片背景去除]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`图片背景去除错误:${logger.red(ret.error)}`)
+ await this.reply(`图片背景去除错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+
+ url = `file://${path}output.png`
+ }
+
+ logger.mark(`[图片背景去除] 发送图片:${logger.blue(url)}`)
+ Running = false
+ await this.reply(segment.image(url), true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/RemoteCommand.js b/Yunzai/plugins/TRSS-Plugin/Apps/RemoteCommand.js
new file mode 100644
index 0000000000000000000000000000000000000000..5110bf852c9b30f695d1109882bd98c1b5d8e75a
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/RemoteCommand.js
@@ -0,0 +1,151 @@
+const htmlDir = `${process.cwd()}/plugins/TRSS-Plugin/Resources/Code/`
+const tplFile = `${htmlDir}Code.html`
+
+export class RemoteCommand extends plugin {
+ constructor() {
+ super({
+ name: "远程命令",
+ dsc: "远程命令",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^rcjp.+",
+ fnc: "RemoteCommandJsPic"
+ },
+ {
+ reg: "^rcj.+",
+ fnc: "RemoteCommandJs"
+ },
+ {
+ reg: "^rcp.+",
+ fnc: "RemoteCommandPic"
+ },
+ {
+ reg: "^rc.+",
+ fnc: "RemoteCommand"
+ }
+ ]
+ })
+ }
+
+ toStr(data) {
+ switch (typeof data) {
+ case "string":
+ return data
+ case "number":
+ return String(data)
+ case "object":
+ if (util.isError(data))
+ return data.stack
+ if (Buffer.isBuffer(data))
+ return Buffer.from(data, "utf8").toString()
+ else
+ return JSON.stringify(data)
+ }
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async evalSync(cmd) {
+ const ret = {}
+ try {
+ ret.stdout = this.toStr(await eval(cmd))
+ } catch (err) {
+ ret.stderr = this.toStr(err)
+ }
+ return ret
+ }
+
+ async RemoteCommandJs(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const cmd = this.e.msg.replace("rcj", "").trim()
+
+ logger.mark(`[远程命令] 执行Js:${logger.blue(cmd)}`)
+ const ret = await this.evalSync(cmd)
+ logger.mark(`[远程命令]\n${ret.stdout}\n${logger.red(ret.stderr)}`)
+
+ if (ret.stdout) {
+ await this.reply(ret.stdout, true)
+ }
+
+ if (ret.stderr) {
+ await this.reply(`错误输出:\n${ret.stderr}`, true)
+ }
+ }
+
+ async RemoteCommandJsPic(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const cmd = this.e.msg.replace("rcjp", "").trim()
+
+ logger.mark(`[远程命令] 执行Js:${logger.blue(cmd)}`)
+ const ret = await this.evalSync(cmd)
+ logger.mark(`[远程命令]\n${ret.stdout}\n${logger.red(ret.stderr)}`)
+
+ if (ret.stdout) {
+ const Code = await ansi_up.ansi_to_html(ret.stdout)
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(img, true)
+ }
+
+ if (ret.stderr) {
+ const Code = await ansi_up.ansi_to_html(ret.stderr)
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(["错误输出:", img], true)
+ }
+ }
+
+ async RemoteCommand(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const cmd = this.e.msg.replace("rc", "").trim()
+
+ logger.mark(`[远程命令] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[远程命令]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.stdout) {
+ await this.reply(ret.stdout.trim(), true)
+ }
+
+ if (ret.stderr) {
+ await this.reply(`标准错误输出:\n${ret.stderr.trim()}`, true)
+ }
+
+ if (ret.error) {
+ logger.error(`远程命令错误:${logger.red(ret.error)}`)
+ await this.reply(`远程命令错误:${ret.error}`, true)
+ }
+ }
+
+ async RemoteCommandPic(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const cmd = this.e.msg.replace("rcp", "").trim()
+
+ logger.mark(`[远程命令] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[远程命令]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.stdout) {
+ const Code = await ansi_up.ansi_to_html(ret.stdout.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(img, true)
+ }
+
+ if (ret.stderr) {
+ const Code = await ansi_up.ansi_to_html(ret.stderr.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(["标准错误输出:", img], true)
+ }
+
+ if (ret.error) {
+ logger.error(`远程命令错误:${logger.red(ret.error)}`)
+ await this.reply(`远程命令错误:${ret.error}`, true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/Script.js b/Yunzai/plugins/TRSS-Plugin/Apps/Script.js
new file mode 100644
index 0000000000000000000000000000000000000000..3a5015d9475ddeba3595d0af902819f6aad629ec
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/Script.js
@@ -0,0 +1,61 @@
+const htmlDir = `${process.cwd()}/plugins/TRSS-Plugin/Resources/Code/`
+const tplFile = `${htmlDir}Code.html`
+const path = `${process.env.HOME}/../`
+const cmdPath = `${path}Main.sh`
+const errorTips = "请使用脚本安装,再使用此功能\nhttps://Yunzai.TRSS.me\nhttps://TRSS.me"
+
+export class Script extends plugin {
+ constructor() {
+ super({
+ name: "脚本执行",
+ dsc: "脚本执行",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^脚本执行.+",
+ fnc: "Script"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async execTask(e, cmd) {
+ logger.mark(`[脚本执行] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[脚本执行]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.stdout) {
+ const Code = await ansi_up.ansi_to_html(ret.stdout.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(img, true)
+ }
+
+ if (ret.stderr) {
+ const Code = await ansi_up.ansi_to_html(ret.stderr.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(["标准错误输出:", img], true)
+ }
+
+ if (ret.error) {
+ logger.error(`脚本执行错误:${logger.red(ret.error)}`)
+ await this.reply(`脚本执行错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+ }
+
+ async Script(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const msg = this.e.msg.replace("脚本执行", "").trim()
+ const cmd = `bash "${cmdPath}" cmd "${msg}"`
+ await this.execTask(e, cmd)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/SourceCode.js b/Yunzai/plugins/TRSS-Plugin/Apps/SourceCode.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad4fd702cb7a49bcbb54c006b9a0c37324f64d58
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/SourceCode.js
@@ -0,0 +1,45 @@
+const htmlDir = `${process.cwd()}/plugins/TRSS-Plugin/Resources/SourceCode/`
+const tplFile = `${htmlDir}SourceCode.html`
+
+export class SourceCode extends plugin {
+ constructor() {
+ super({
+ name: "SourceCode",
+ dsc: "SourceCode",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^sc.+",
+ fnc: "SourceCode"
+ }
+ ]
+ })
+ }
+
+ async SourceCode(e) {
+ if(!(this.e.isMaster||this.e.user_id == 2536554304))return false
+ const msg = this.e.msg.replace("sc", "").trim()
+ logger.mark(`[SourceCode] 查看:${logger.blue(msg)}`)
+
+ let scFile = msg
+ if (/^https?:\/\//.test(msg)) {
+ scFile =`${process.cwd()}/data/cache.sc`
+ const ret = await common.downFile(msg, scFile)
+ if (!ret) {
+ await this.reply("文件下载错误", true)
+ return false
+ }
+ }
+
+ if (!(fs.existsSync(scFile) && fs.statSync(scFile).isFile())) {
+ await this.reply("文件不存在", true)
+ return false
+ }
+
+ const SourceCode = fs.readFileSync(scFile, "utf-8").replace(/ /g, " ")
+ const img = await puppeteer.screenshot("SourceCode", { tplFile, htmlDir, SourceCode })
+
+ await this.reply(img, true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/SystemInfo.js b/Yunzai/plugins/TRSS-Plugin/Apps/SystemInfo.js
new file mode 100644
index 0000000000000000000000000000000000000000..ce3f1366e36346b5e1d75ff6580f2d413b9876ec
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/SystemInfo.js
@@ -0,0 +1,103 @@
+const htmlDir = `${process.cwd()}/plugins/TRSS-Plugin/Resources/Code/`
+const tplFile = `${htmlDir}Code.html`
+const errorTips = "未使用脚本安装,此功能出错属于正常情况\nhttps://TRSS.me"
+
+let cmd = "fastfetch"
+let cmds
+let benchcmd = "bash <(curl -L bench.sh)"
+let Running
+
+if (process.platform == "win32") {
+ cmds = `bash -c "${cmd} --stdout"`
+ cmd = `bash -c "${cmd}"`
+ benchcmd = `bash -c "${benchcmd}"`
+} else {
+ cmds = `${cmd} --pipe`
+}
+
+export class SystemInfo extends plugin {
+ constructor() {
+ super({
+ name: "系统信息",
+ dsc: "系统信息",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: "^#?系统信息$",
+ fnc: "SystemInfo"
+ },
+ {
+ reg: "^#?系统信息图片$",
+ fnc: "SystemInfoPic"
+ },
+ {
+ reg: "^#?系统测试$",
+ fnc: "SystemBench"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async SystemInfo(e) {
+ logger.mark(`[系统信息] 执行:${logger.blue(cmds)}`)
+ const ret = await this.execSync(cmds)
+ logger.mark(`[系统信息]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`系统信息错误:${logger.red(ret.error)}`)
+ await this.reply(`系统信息错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+
+ await this.reply(ret.stdout.trim(), true)
+ }
+
+ async SystemInfoPic(e) {
+ logger.mark(`[系统信息] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(`${cmd}`)
+ logger.mark(`[系统信息]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`系统信息错误:${logger.red(ret.error)}`)
+ await this.reply(`系统信息错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+
+ const Code = await ansi_up.ansi_to_html(ret.stdout.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(img, true)
+ }
+
+ async SystemBench(e) {
+ if (Running) {
+ await this.reply("正在测试,请稍等……", true)
+ return false
+ }
+ Running = true
+ await this.reply("开始测试,请稍等……", true)
+
+ logger.mark(`[系统测试] 执行:${logger.blue(benchcmd)}`)
+ const ret = await this.execSync(`${benchcmd}`)
+ logger.mark(`[系统测试]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`系统测试错误:${logger.red(ret.error)}`)
+ await this.reply(`系统测试错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+
+ const Code = await ansi_up.ansi_to_html(ret.stdout.trim())
+ const img = await puppeteer.screenshot("Code", { tplFile, htmlDir, Code })
+ await this.reply(img, true)
+ Running = false
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/Voice.js b/Yunzai/plugins/TRSS-Plugin/Apps/Voice.js
new file mode 100644
index 0000000000000000000000000000000000000000..374738f8b350d9d804ba9fcde2fa616a7afad8d8
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/Voice.js
@@ -0,0 +1,120 @@
+import gsCfg from "../../genshin/model/gsCfg.js"
+
+const GenshinVoicePath = `${process.cwd()}/plugins/TRSS-Plugin/GenshinVoice/`
+const ChatWaifuPath = `${process.cwd()}/plugins/TRSS-Plugin/ChatWaifu/`
+const errorTips = "请查看安装使用教程:\nhttps://Yunzai.TRSS.me\n并将报错通过联系方式反馈给开发者"
+
+const AllAbbr = gsCfg.getAllAbbr()
+const GenshinVoiceSpeakers = ["派蒙", "凯亚", "安柏", "丽莎", "琴", "香菱", "枫原万叶", "迪卢克", "温迪", "可莉", "早柚", "托马", "芭芭拉", "优菈", "云堇", "钟离", "魈", "凝光", "雷电将军", "北斗", "甘雨", "七七", "刻晴", "神里绫华", "戴因斯雷布", "雷泽", "神里绫人", "罗莎莉亚", "阿贝多", "八重神子", "宵宫", "荒泷一斗", "九条裟罗", "夜兰", "珊瑚宫心海", "五郎", "散兵", "女士", "达达利亚", "莫娜", "班尼特", "申鹤", "行秋", "烟绯", "久岐忍", "辛焱", "砂糖", "胡桃", "重云", "菲谢尔", "诺艾尔", "迪奥娜", "鹿野院平藏"]
+const ChatWaifuSpeakers = ["綾地寧々", "在原七海", "小茸", "唐乐吟", "綾地寧々J", "因幡めぐるJ", "朝武芳乃J", "常陸茉子J", "ムラサメJ", "鞍馬小春J", "在原七海J", "綾地寧々H", "因幡めぐるH", "朝武芳乃H", "常陸茉子H", "ムラサメH", "鞍馬小春H", "在原七海H"]
+
+let Running
+
+export class Voice extends plugin {
+ constructor() {
+ super({
+ name: "语音合成",
+ dsc: "语音合成",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: ".+(转码)?说.+",
+ fnc: "Voice"
+ },
+ {
+ reg: "#?语音(合成)?(角色)?列表$",
+ fnc: "VoiceList"
+ }
+ ]
+ })
+ }
+
+ async execSync(cmd) {
+ return new Promise(resolve => {
+ exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ async Voice() {
+ const msg = this.e.msg.split("说")
+ let speaker = msg.shift()
+ const text = msg.join("说").replace("'", "").trim()
+
+ let transcoding = false
+ if (speaker.match("转码")) {
+ speaker = speaker.replace("转码", "")
+ transcoding = true
+ }
+
+ let url
+ let path
+ let speakerid
+ if (ChatWaifuSpeakers.indexOf(speaker) != -1){
+ speakerid = ChatWaifuSpeakers.indexOf(speaker)
+ if (config.Voice.ChatWaifuApi) {
+ url = `${config.Voice.ChatWaifuApi}?user_id=${this.e.user_id}&bot_id=${this.e.self_id}&id=${speakerid}&text=${encodeURIComponent(text)}`
+ } else {
+ path = ChatWaifuPath
+ }
+ } else {
+ if (GenshinVoiceSpeakers.indexOf(speaker) == -1) {
+ for (const rolename of Object.values(AllAbbr)) {
+ if (rolename.includes(speaker)) {
+ speaker = rolename[0]
+ break
+ }
+ }
+
+ if (GenshinVoiceSpeakers.indexOf(speaker) == -1) {
+ logger.warn(`[语音合成] 不存在该角色:${logger.yellow(speaker)}`)
+ return false
+ }
+ }
+
+ speakerid = GenshinVoiceSpeakers.indexOf(speaker)
+ if (config.Voice.GenshinVoiceApi) {
+ url = `${config.Voice.GenshinVoiceApi}?user_id=${this.e.user_id}&bot_id=${this.e.self_id}&id=${speakerid}&text=${encodeURIComponent(text)}`
+ } else {
+ path = GenshinVoicePath
+ }
+ }
+
+ logger.mark(`[语音合成] ${logger.blue(`${speaker}(${speakerid})`)} 说 ${logger.cyan(text)}`)
+
+ if (Running) {
+ await this.reply("正在生成,请稍等……", true)
+ return false
+ }
+ Running = true
+
+ if (path) {
+ const cmd = `bash '${path}main.sh' output.wav ${speakerid} '${text}'`
+
+ logger.mark(`[语音合成] 执行:${logger.blue(cmd)}`)
+ const ret = await this.execSync(cmd)
+ logger.mark(`[语音合成]\n${ret.stdout.trim()}\n${logger.red(ret.stderr.trim())}`)
+
+ if (ret.error) {
+ logger.error(`语音合成错误:${logger.red(ret.error)}`)
+ await this.reply(`语音合成错误:${ret.error}`, true)
+ await this.reply(errorTips)
+ }
+ url = `file://${path}output.wav`
+ }
+
+ logger.mark(`[语音合成] 发送语音:${logger.blue(url)}`)
+ Running = false
+ await this.reply(await uploadRecord(url, 68714, transcoding))
+ }
+
+ async VoiceList() {
+ await this.reply(await common.makeForwardMsg(this.e, [
+ "https://Yunzai.TRSS.me",
+ GenshinVoiceSpeakers.join("\n"),
+ ChatWaifuSpeakers.join("\n"),
+ ], "TRSS-Plugin 语音合成角色列表"))
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Apps/miHoYoLogin.js b/Yunzai/plugins/TRSS-Plugin/Apps/miHoYoLogin.js
new file mode 100644
index 0000000000000000000000000000000000000000..d60be3ebbfcfd2395cd7b0f0ec2e3762494f2b36
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Apps/miHoYoLogin.js
@@ -0,0 +1,280 @@
+import _ from "lodash"
+import crypto from "crypto"
+import fetch from "node-fetch"
+
+const regex = "^#?(米哈?游社?登(录|陆|入)|登(录|陆|入)米哈?游社?)"
+const publicKey = `-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDvekdPMHN3AYhm/vktJT+YJr7cI5DcsNKqdsx5DZX0gDuWFuIjzdwButrIYPNmRJ1G8ybDIF7oDW2eEpm5sMbL9zs
+9ExXCdvqrn51qELbqj0XxtMTIpaCHFSI50PfPpTFV9Xt/hmyVwokoOXFlAEgCn+Q
+CgGs52bFoYMtyi+xEQIDAQAB
+-----END PUBLIC KEY-----`
+const app_id = 8
+
+function random_string(n) {
+ return _.sampleSize("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", n).join("")
+}
+
+function encrypt_data(data) {
+ return crypto.publicEncrypt({
+ key: publicKey,
+ padding: crypto.constants.RSA_PKCS1_PADDING
+ }, data).toString("base64")
+}
+
+function md5(data) {
+ return crypto.createHash("md5").update(data).digest("hex")
+}
+
+function ds(data) {
+ const t = Math.floor(Date.now()/1000)
+ const r = random_string(6)
+ const h = md5(`salt=JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS&t=${t}&r=${r}&b=${data}&q=`)
+ return `${t},${r},${h}`
+}
+
+function sleep(ms) {
+ return new Promise(resolve=>setTimeout(resolve, ms))
+}
+
+async function request(url, data, aigis) {
+ return await fetch(url, {
+ method: "post",
+ body: data,
+ headers: {
+ "x-rpc-app_version": "2.41.0",
+ "DS": ds(data),
+ "x-rpc-aigis": aigis,
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ "x-rpc-game_biz": "bbs_cn",
+ "x-rpc-sys_version": "12",
+ "x-rpc-device_id": random_string(16),
+ "x-rpc-device_fp": random_string(13),
+ "x-rpc-device_name": random_string(16),
+ "x-rpc-device_model": random_string(16),
+ "x-rpc-app_id": "bll8iq97cem8",
+ "x-rpc-client_type": "2",
+ "User-Agent": "okhttp/4.8.0"
+ }
+ })
+}
+
+const errorTips = "登录失败,请检查日志\nhttps://Yunzai.TRSS.me"
+const accounts = {}
+const Running = {}
+
+export class miHoYoLogin extends plugin {
+ constructor() {
+ super({
+ name: "米哈游登录",
+ dsc: "米哈游登录",
+ event: "message",
+ priority: 10,
+ rule: [
+ {
+ reg: `${regex}$`,
+ fnc: "miHoYoLoginQRCode"
+ },
+ {
+ reg: `${regex}.+$`,
+ fnc: "miHoYoLoginDetect"
+ },
+ {
+ reg: "^#?(体力|(c|C)(oo)?k(ie)?|(s|S)(to)?k(en)?)(帮助|教程)$",
+ fnc: "miHoYoLoginHelp"
+ }
+ ]
+ })
+ }
+
+ miHoYoLoginDetect() {
+ accounts[this.e.user_id] = this.e
+ this.setContext("miHoYoLogin")
+ this.reply("请发送密码", true, { recallMsg: 60 })
+ }
+
+ async crack_geetest(gt, challenge) {
+ let res
+ this.reply(`请完成验证:https://challenge.minigg.cn/manual/index.html?gt=${gt}&challenge=${challenge}`, true, { recallMsg: 60 })
+ for (let n=1;n<60;n++) {
+ await sleep(5000)
+ try {
+ res = await fetch(`https://challenge.minigg.cn/manual/?callback=${challenge}`)
+ res = await res.json()
+ if (res.retcode == 200)
+ return res.data
+ } catch (err) {
+ logger.error(`[米哈游登录] 错误:${logger.red(err)}`)
+ }
+ }
+ this.reply("验证超时", true)
+ return false
+ }
+
+ async miHoYoLogin() {
+ if(!this.e.msg)return false
+ this.finish("miHoYoLogin")
+ if (Running[this.e.user_id]) {
+ this.reply("有正在进行的登录操作,请完成后再试……", true, { recallMsg: 60 })
+ return false
+ }
+ Running[this.e.user_id] = true
+
+ const password = this.e.msg.trim()
+ this.e = accounts[this.e.user_id]
+ const account = this.e.msg.replace(new RegExp(regex), "").trim()
+
+ const data = JSON.stringify({
+ account: encrypt_data(account),
+ password: encrypt_data(password)
+ })
+
+ const url = "https://passport-api.mihoyo.com/account/ma-cn-passport/app/loginByPassword"
+ let res = await request(url, data, "")
+ const aigis_data = JSON.parse(res.headers.get("x-rpc-aigis"))
+ res = await res.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+
+ if (res.retcode == -3101) {
+ logger.mark("[米哈游登录] 正在验证")
+ const aigis_captcha_data = JSON.parse(aigis_data.data)
+ const challenge = aigis_captcha_data.challenge
+ const validate = await this.crack_geetest(aigis_captcha_data.gt, challenge)
+ if (validate.geetest_validate) {
+ logger.mark("[米哈游登录] 验证成功")
+ } else {
+ logger.error("[米哈游登录] 验证失败")
+ Running[this.e.user_id] = false
+ return false
+ }
+
+ const aigis = aigis_data.session_id + ";" + Buffer.from(JSON.stringify({
+ geetest_challenge: challenge,
+ geetest_seccode: validate.geetest_validate + "|jordan",
+ geetest_validate: validate.geetest_validate
+ })).toString("base64")
+
+ res = await request(url, data, aigis)
+ res = await res.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+ }
+
+ if (res.retcode != 0) {
+ this.reply(`错误:${JSON.stringify(res)}`, true)
+ Running[this.e.user_id] = false
+ return false
+ }
+
+ let cookie = await fetch(`https://api-takumi.mihoyo.com/auth/api/getCookieAccountInfoBySToken?stoken=${res.data.token.token}&mid=${res.data.user_info.mid}`)
+ cookie = await cookie.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(cookie))}`)
+ cookie = [
+ `ltoken=${res.data.token.token};ltuid=${res.data.user_info.aid};cookie_token=${cookie.data.cookie_token};login_ticket=${res.data.login_ticket}`,
+ `stoken=${res.data.token.token};stuid=${res.data.user_info.aid};mid=${res.data.user_info.mid}`,
+ ]
+ for (const i of cookie) this.makeMessage(i)
+ if (this.e.isPrivate)
+ this.reply(await common.makeForwardMsg(this.e, cookie, "登录完成,以下分别是 Cookie 和 Stoken,将会自动绑定"))
+
+ Running[this.e.user_id] = false
+ }
+
+ async miHoYoLoginQRCode() {
+ if (Running[this.e.user_id]) {
+ this.reply("有正在进行的登录操作,请完成后再试……", true, { recallMsg: 60 })
+ return false
+ }
+ Running[this.e.user_id] = true
+
+ const device = random_string(64)
+ let res = await fetch("https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/fetch", {
+ method: "post",
+ body: JSON.stringify({ app_id, device })
+ })
+ res = await res.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+
+ const url = res.data.url
+ const ticket = url.split("ticket=")[1]
+ const img = (await QR.toDataURL(url)).replace("data:image/png;base64,", "base64://")
+ this.reply(["请使用米游社扫码登录", segment.image(img)], true, { recallMsg: 60 })
+
+ let data
+ let Scanned
+ for (let n=1;n<60;n++) {
+ await sleep(5000)
+ try {
+ res = await fetch("https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/query", {
+ method: "post",
+ body: JSON.stringify({ app_id, device, ticket })
+ })
+ res = await res.json()
+
+ if (res.retcode != 0) {
+ this.reply("二维码已过期,请重新登录", true, { recallMsg: 60 })
+ Running[this.e.user_id] = false
+ return false
+ }
+
+ if (res.data.stat == "Scanned" && !Scanned) {
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+ Scanned = true
+ this.reply("二维码已扫描,请确认登录", true, { recallMsg: 60 })
+ }
+
+ if (res.data.stat == "Confirmed") {
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+ data = JSON.parse(res.data.payload.raw)
+ break
+ }
+ } catch (err) {
+ logger.error(`[米哈游登录] 错误:${logger.red(err)}`)
+ }
+ }
+
+ if (!(data.uid&&data.token)) {
+ this.reply(errorTips, true)
+ Running[this.e.user_id] = false
+ return false
+ }
+
+ res = await request(
+ "https://passport-api.mihoyo.com/account/ma-cn-session/app/getTokenByGameToken",
+ JSON.stringify({ account_id: parseInt(data.uid), game_token: data.token }),
+ ""
+ )
+ res = await res.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(res))}`)
+
+ let cookie = await fetch(`https://api-takumi.mihoyo.com/auth/api/getCookieAccountInfoByGameToken?account_id=${data.uid}&game_token=${data.token}`)
+ cookie = await cookie.json()
+ logger.mark(`[米哈游登录] ${logger.blue(JSON.stringify(cookie))}`)
+
+ cookie = [
+ `ltoken=${res.data.token.token};ltuid=${res.data.user_info.aid};cookie_token=${cookie.data.cookie_token}`,
+ `stoken=${res.data.token.token};stuid=${res.data.user_info.aid};mid=${res.data.user_info.mid}`,
+ ]
+ for (const i of cookie) this.makeMessage(i)
+ if (this.e.isPrivate)
+ this.reply(await common.makeForwardMsg(this.e, cookie, "登录完成,以下分别是 Cookie 和 Stoken,将会自动绑定"))
+
+ Running[this.e.user_id] = false
+ }
+
+ makeMessage(msg) {
+ Bot.emit("message", {
+ ...this.e,
+ isGroup: undefined,
+ msg: undefined,
+ original_msg: undefined,
+ message_type: "private",
+ message: [{ type: "text", text: msg }],
+ raw_message: msg,
+ })
+ }
+
+ miHoYoLoginHelp() {
+ if (!config.miHoYoLogin.help) return false
+ this.reply("二维码登录:发送【米哈游登录】\n账号密码登录:发送【米哈游登录 账号】", true)
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Model/config.js b/Yunzai/plugins/TRSS-Plugin/Model/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..6cef7bca2e3d8fd4eb55d460d496b7680013f731
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Model/config.js
@@ -0,0 +1,51 @@
+import fs from "fs"
+import YAML from "yaml"
+import _ from "lodash"
+
+const configFile = "config/TRSS.yaml"
+const configFileOld = "plugins/TRSS-Plugin/config.yaml"
+if (fs.existsSync(configFileOld))
+ fs.renameSync(configFileOld, configFile)
+
+const config = {
+ tips: "",
+
+ Voice: {
+ GenshinVoiceApi: "",
+ ChatWaifuApi: ""
+ },
+
+ RealESRGAN: {
+ api: "",
+ format: "jpg"
+ },
+
+ RemBG: {
+ api: ""
+ },
+
+ miHoYoLogin: {
+ help: true
+ }
+}
+
+let configData
+
+if (fs.existsSync(configFile))
+ try {
+ configData = YAML.parse(fs.readFileSync(configFile, "utf-8"))
+ _.merge(config, configData)
+ } catch (err) {
+ logger.error(`配置文件 读取失败:${logger.red(err)}`)
+ }
+
+config.tips = [
+ "欢迎使用 TRSS Yunzai Plugin ! 作者:时雨🌌星空",
+ "按 Ctrl+Q Y 保存退出",
+ "参考:https://Yunzai.TRSS.me"
+]
+
+if (YAML.stringify(config) != YAML.stringify(configData))
+ fs.writeFileSync(configFile, YAML.stringify(config), "utf-8")
+
+export default config
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Model/uploadRecord.js b/Yunzai/plugins/TRSS-Plugin/Model/uploadRecord.js
new file mode 100644
index 0000000000000000000000000000000000000000..5edcf30468e236c95b65bdafae9e4d5d785cba1e
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Model/uploadRecord.js
@@ -0,0 +1,427 @@
+import { core } from "oicq"
+import common from "oicq"
+import Contactable from "oicq"
+import querystring from "querystring"
+import fetch from "node-fetch"
+import fs from "fs"
+import path from "path"
+import os from "os"
+import util from "util"
+import stream from "stream"
+import crypto from "crypto"
+import child_process from "child_process"
+var errors = {};
+
+
+async function uploadRecord(record_url, seconds = 0,transcoding = true) {
+ const result = await getPttBuffer(record_url, Bot.config.ffmpeg_path, transcoding);
+ if(!result.buffer){
+ return false;
+ }
+ let buf = result.buffer;
+ if(seconds == 0 && result.time) seconds = result.time.seconds;
+ const hash = (0, md5)(buf);
+ const codec = String(buf.slice(0, 7)).includes("SILK") ? (transcoding ? 1 : 0) : 0;
+ const body = core.pb.encode({
+ 1: 3,
+ 2: 3,
+ 5: {
+ 1: Contactable.target,
+ 2: Bot.uin,
+ 3: 0,
+ 4: hash,
+ 5: buf.length,
+ 6: hash,
+ 7: 5,
+ 8: 9,
+ 9: 4,
+ 11: 0,
+ 10: Bot.apk.version,
+ 12: 1,
+ 13: 1,
+ 14: codec,
+ 15: 1,
+ },
+ });
+ const payload = await Bot.sendUni("PttStore.GroupPttUp", body);
+ const rsp = core.pb.decode(payload)[5];
+ rsp[2] && (0, errors.drop)(rsp[2], rsp[3]);
+ const ip = rsp[5]?.[0] || rsp[5], port = rsp[6]?.[0] || rsp[6];
+ const ukey = rsp[7].toHex(), filekey = rsp[11].toHex();
+ const params = {
+ ver: 4679,
+ ukey, filekey,
+ filesize: buf.length,
+ bmd5: hash.toString("hex"),
+ mType: "pttDu",
+ voice_encodec: codec
+ };
+ const url = `http://${(0, int32ip2str)(ip)}:${port}/?` + querystring.stringify(params);
+ const headers = {
+ "User-Agent": `QQ/${Bot.apk.version} CFNetwork/1126`,
+ "Net-Type": "Wifi"
+ };
+ await fetch(url,{
+ method: 'POST',//post请求
+ headers: headers,
+ body: buf
+ });
+ //await axios.post(url, buf, { headers });
+
+ const fid = rsp[11].toBuffer();
+ const b = core.pb.encode({
+ 1: 4,
+ 2: Bot.uin,
+ 3: fid,
+ 4: hash,
+ 5: hash.toString("hex") + ".amr",
+ 6: seconds,
+ 11: 1,
+ 18: fid,
+ 19: seconds,
+ 30: Buffer.from([8, 0, 40, 0, 56, 0]),
+ });
+ return {
+ type: "record", file: "protobuf://" + Buffer.from(b).toString("base64")
+ };
+}
+
+export default uploadRecord
+
+async function getPttBuffer(file, ffmpeg = "ffmpeg", transcoding = true) {
+ let buffer;
+ let time;
+ if (file instanceof Buffer || file.startsWith("base64://")) {
+ // Buffer或base64
+ const buf = file instanceof Buffer ? file : Buffer.from(file.slice(9), "base64");
+ const head = buf.slice(0, 7).toString();
+ if (head.includes("SILK") || head.includes("AMR") || !transcoding) {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)());
+ await fs.promises.writeFile(tmpfile, buf);
+ let result = await getAudioTime(tmpfile,ffmpeg);
+ if(result.code == 1) time = result.data;
+ fs.unlink(tmpfile,NOOP);
+ buffer = buf;
+ }else {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)());
+ let result = await getAudioTime(tmpfile,ffmpeg);
+ if(result.code == 1) time = result.data;
+ await fs.promises.writeFile(tmpfile, buf);
+ buffer = await audioTrans(tmpfile, ffmpeg);
+ }
+ }
+ else if (file.startsWith("http://") || file.startsWith("https://")) {
+ // 网络文件
+ //const readable = (await axios.get(file, { responseType: "stream" })).data;
+ try{
+ const headers = {
+ "User-Agent": `Dalvik/2.1.0 (Linux; U; Android 12; MI 9 Build/SKQ1.211230.001)`,
+ };
+ let response = await fetch(file,{
+ method: 'GET',//post请求
+ headers: headers
+ });
+ const buf = Buffer.from(await response.arrayBuffer());
+ const tmpfile = path.join(TMP_DIR, (0, uuid)());
+ await fs.promises.writeFile(tmpfile, buf);
+ //await (0, pipeline)(readable.pipe(new DownloadTransform), fs.createWriteStream(tmpfile));
+ const head = await read7Bytes(tmpfile);
+ let result = await getAudioTime(tmpfile,ffmpeg);
+ if(result.code == 1) time = result.data;
+ if (head.includes("SILK") || head.includes("AMR") || !transcoding) {
+ //const buf = await fs.promises.readFile(tmpfile);
+ fs.unlink(tmpfile,NOOP);
+ buffer = buf;
+ } else {
+ buffer = await audioTrans(tmpfile, ffmpeg);
+ }
+ }catch(err){}
+ }
+ else {
+ // 本地文件
+ file = String(file).replace(/^file:\/{2}/, "");
+ IS_WIN && file.startsWith("/") && (file = file.slice(1));
+ const head = await read7Bytes(file);
+ let result = await getAudioTime(file,ffmpeg);
+ if(result.code == 1) time = result.data;
+ if (head.includes("SILK") || head.includes("AMR") || !transcoding) {
+ buffer = await fs.promises.readFile(file);
+ } else {
+ buffer = await audioTrans(file, ffmpeg);
+ }
+ }
+ return {buffer: buffer, time: time}
+}
+
+async function getAudioTime(file, ffmpeg = "ffmpeg") {
+ return new Promise((resolve, reject) => {
+ (0, child_process.exec)(`${ffmpeg} -i "${file}"`, async (error, stdout, stderr) => {
+ try {
+ let time = stderr.split('Duration:')[1]?.split(',')[0].trim();
+ let arr = time?.split(':');
+ arr.reverse();
+ let n = 1;
+ let s = 0;
+ for(let val of arr){
+ if(parseInt(val) > 0) s += parseInt(val) * n;
+ n *= 60;
+ }
+ resolve({code: 1,data: {
+ time: time,
+ seconds: s,
+ exec_text: stderr
+ }});
+ }
+ catch {
+ resolve({code: -1});
+ }
+ });
+ });
+}
+
+async function audioTrans(file, ffmpeg = "ffmpeg") {
+ return new Promise((resolve, reject) => {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)());
+ (0, child_process.exec)(`${ffmpeg} -y -i "${file}" -ac 1 -ar 8000 -f amr "${tmpfile}"`, async (error, stdout, stderr) => {
+ try {
+ const amr = await fs.promises.readFile(tmpfile);
+ resolve(amr);
+ }
+ catch {
+ reject(new core.ApiRejection(errors.ErrorCode.FFmpegPttTransError, "音频转码到amr失败,请确认你的ffmpeg可以处理此转换"));
+ }
+ finally {
+ fs.unlink(tmpfile, NOOP);
+ }
+ });
+ });
+}
+
+async function read7Bytes(file) {
+ const fd = await fs.promises.open(file, "r");
+ const buf = (await fd.read(Buffer.alloc(7), 0, 7, 0)).buffer;
+ fd.close();
+ return buf;
+}
+
+function uuid() {
+ let hex = crypto.randomBytes(16).toString("hex");
+ return hex.substr(0, 8) + "-" + hex.substr(8, 4) + "-" + hex.substr(12, 4) + "-" + hex.substr(16, 4) + "-" + hex.substr(20);
+}
+
+/** 计算流的md5 */
+function md5Stream(readable) {
+ return new Promise((resolve, reject) => {
+ readable.on("error", reject);
+ readable.pipe(crypto.createHash("md5")
+ .on("error", reject)
+ .on("data", resolve));
+ });
+}
+
+/** 计算文件的md5和sha */
+function fileHash(filepath) {
+ const readable = fs.createReadStream(filepath);
+ const sha = new Promise((resolve, reject) => {
+ readable.on("error", reject);
+ readable.pipe(crypto.createHash("sha1")
+ .on("error", reject)
+ .on("data", resolve));
+ });
+ return Promise.all([md5Stream(readable), sha]);
+}
+
+/** 群号转uin */
+function code2uin(code) {
+ let left = Math.floor(code / 1000000);
+ if (left >= 0 && left <= 10)
+ left += 202;
+ else if (left >= 11 && left <= 19)
+ left += 469;
+ else if (left >= 20 && left <= 66)
+ left += 2080;
+ else if (left >= 67 && left <= 156)
+ left += 1943;
+ else if (left >= 157 && left <= 209)
+ left += 1990;
+ else if (left >= 210 && left <= 309)
+ left += 3890;
+ else if (left >= 310 && left <= 335)
+ left += 3490;
+ else if (left >= 336 && left <= 386)
+ left += 2265;
+ else if (left >= 387 && left <= 499)
+ left += 3490;
+ return left * 1000000 + code % 1000000;
+}
+
+/** uin转群号 */
+function uin2code(uin) {
+ let left = Math.floor(uin / 1000000);
+ if (left >= 202 && left <= 212)
+ left -= 202;
+ else if (left >= 480 && left <= 488)
+ left -= 469;
+ else if (left >= 2100 && left <= 2146)
+ left -= 2080;
+ else if (left >= 2010 && left <= 2099)
+ left -= 1943;
+ else if (left >= 2147 && left <= 2199)
+ left -= 1990;
+ else if (left >= 2600 && left <= 2651)
+ left -= 2265;
+ else if (left >= 3800 && left <= 3989)
+ left -= 3490;
+ else if (left >= 4100 && left <= 4199)
+ left -= 3890;
+ return left * 1000000 + uin % 1000000;
+}
+
+function int32ip2str(ip) {
+ if (typeof ip === "string")
+ return ip;
+ ip = ip & 0xffffffff;
+ return [
+ ip & 0xff,
+ (ip & 0xff00) >> 8,
+ (ip & 0xff0000) >> 16,
+ (ip & 0xff000000) >> 24 & 0xff,
+ ].join(".");
+}
+
+/** 解析彩色群名片 */
+function parseFunString(buf) {
+ if (buf[0] === 0xA) {
+ let res = "";
+ try {
+ let arr = core.pb.decode(buf)[1];
+ if (!Array.isArray(arr))
+ arr = [arr];
+ for (let v of arr) {
+ if (v[2])
+ res += String(v[2]);
+ }
+ }
+ catch { }
+ return res;
+ }
+ else {
+ return String(buf);
+ }
+}
+
+/** xml转义 */
+function escapeXml(str) {
+ return str.replace(/[&"><]/g, function (s) {
+ if (s === "&")
+ return "&";
+ if (s === "<")
+ return "<";
+ if (s === ">")
+ return ">";
+ if (s === "\"")
+ return """;
+ return "";
+ });
+}
+
+/** 用于下载限量 */
+class DownloadTransform extends stream.Transform {
+ constructor() {
+ super(...arguments);
+ this._size = 0;
+ }
+ _transform(data, encoding, callback) {
+ this._size += data.length;
+ let error = null;
+ if (this._size <= MAX_UPLOAD_SIZE)
+ this.push(data);
+ else
+ error = new Error("downloading over 30MB is refused");
+ callback(error);
+ }
+}
+const IS_WIN = os.platform() === "win32";
+/** 系统临时目录,用于临时存放下载的图片等内容 */
+const TMP_DIR = os.tmpdir();
+/** 最大上传和下载大小,以图片上传限制为准:30MB */
+const MAX_UPLOAD_SIZE = 31457280;
+
+/** no operation */
+const NOOP = () => { };
+
+/** promisified pipeline */
+const pipeline = (0, util.promisify)(stream.pipeline);
+/** md5 hash */
+const md5 = (data) => (0, crypto.createHash)("md5").update(data).digest();
+
+
+errors.LoginErrorCode = errors.drop = errors.ErrorCode = void 0;
+var ErrorCode;
+(function (ErrorCode) {
+ /** 客户端离线 */
+ ErrorCode[ErrorCode["ClientNotOnline"] = -1] = "ClientNotOnline";
+ /** 发包超时未收到服务器回应 */
+ ErrorCode[ErrorCode["PacketTimeout"] = -2] = "PacketTimeout";
+ /** 用户不存在 */
+ ErrorCode[ErrorCode["UserNotExists"] = -10] = "UserNotExists";
+ /** 群不存在(未加入) */
+ ErrorCode[ErrorCode["GroupNotJoined"] = -20] = "GroupNotJoined";
+ /** 群员不存在 */
+ ErrorCode[ErrorCode["MemberNotExists"] = -30] = "MemberNotExists";
+ /** 发消息时传入的参数不正确 */
+ ErrorCode[ErrorCode["MessageBuilderError"] = -60] = "MessageBuilderError";
+ /** 群消息被风控发送失败 */
+ ErrorCode[ErrorCode["RiskMessageError"] = -70] = "RiskMessageError";
+ /** 群消息有敏感词发送失败 */
+ ErrorCode[ErrorCode["SensitiveWordsError"] = -80] = "SensitiveWordsError";
+ /** 上传图片/文件/视频等数据超时 */
+ ErrorCode[ErrorCode["HighwayTimeout"] = -110] = "HighwayTimeout";
+ /** 上传图片/文件/视频等数据遇到网络错误 */
+ ErrorCode[ErrorCode["HighwayNetworkError"] = -120] = "HighwayNetworkError";
+ /** 没有上传通道 */
+ ErrorCode[ErrorCode["NoUploadChannel"] = -130] = "NoUploadChannel";
+ /** 不支持的file类型(没有流) */
+ ErrorCode[ErrorCode["HighwayFileTypeError"] = -140] = "HighwayFileTypeError";
+ /** 文件安全校验未通过不存在 */
+ ErrorCode[ErrorCode["UnsafeFile"] = -150] = "UnsafeFile";
+ /** 离线(私聊)文件不存在 */
+ ErrorCode[ErrorCode["OfflineFileNotExists"] = -160] = "OfflineFileNotExists";
+ /** 群文件不存在(无法转发) */
+ ErrorCode[ErrorCode["GroupFileNotExists"] = -170] = "GroupFileNotExists";
+ /** 获取视频中的图片失败 */
+ ErrorCode[ErrorCode["FFmpegVideoThumbError"] = -210] = "FFmpegVideoThumbError";
+ /** 音频转换失败 */
+ ErrorCode[ErrorCode["FFmpegPttTransError"] = -220] = "FFmpegPttTransError";
+})(ErrorCode = errors.ErrorCode || (errors.ErrorCode = {}));
+const ErrorMessage = {
+ [ErrorCode.UserNotExists]: "查无此人",
+ [ErrorCode.GroupNotJoined]: "未加入的群",
+ [ErrorCode.MemberNotExists]: "幽灵群员",
+ [ErrorCode.RiskMessageError]: "群消息发送失败,可能被风控",
+ [ErrorCode.SensitiveWordsError]: "群消息发送失败,请检查消息内容",
+ 10: "消息过长",
+ 34: "消息过长",
+ 120: "在该群被禁言",
+ 121: "AT全体剩余次数不足"
+};
+function drop(code, message) {
+ if (!message || !message.length)
+ message = ErrorMessage[code];
+ throw new core.ApiRejection(code, message);
+}
+errors.drop = drop;
+/** 登录时可能出现的错误,不在列的都属于未知错误,暂时无法解决 */
+var LoginErrorCode;
+(function (LoginErrorCode) {
+ /** 密码错误 */
+ LoginErrorCode[LoginErrorCode["WrongPassword"] = 1] = "WrongPassword";
+ /** 账号被冻结 */
+ LoginErrorCode[LoginErrorCode["AccountFrozen"] = 40] = "AccountFrozen";
+ /** 发短信太频繁 */
+ LoginErrorCode[LoginErrorCode["TooManySms"] = 162] = "TooManySms";
+ /** 短信验证码错误 */
+ LoginErrorCode[LoginErrorCode["WrongSmsCode"] = 163] = "WrongSmsCode";
+ /** 滑块ticket错误 */
+ LoginErrorCode[LoginErrorCode["WrongTicket"] = 237] = "WrongTicket";
+})(LoginErrorCode = errors.LoginErrorCode || (errors.LoginErrorCode = {}));
\ No newline at end of file
diff --git "a/Yunzai/plugins/TRSS-Plugin/Picture/Microsoft_C++_\347\224\237\346\210\220\345\267\245\345\205\267.png" "b/Yunzai/plugins/TRSS-Plugin/Picture/Microsoft_C++_\347\224\237\346\210\220\345\267\245\345\205\267.png"
new file mode 100644
index 0000000000000000000000000000000000000000..17da1cdb6726ee38f01aa0adc1298ede44caf7ef
Binary files /dev/null and "b/Yunzai/plugins/TRSS-Plugin/Picture/Microsoft_C++_\347\224\237\346\210\220\345\267\245\345\205\267.png" differ
diff --git "a/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217.png" "b/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217.png"
new file mode 100644
index 0000000000000000000000000000000000000000..c7a6a31db7fbd0045652a2d5662db06151c2364e
--- /dev/null
+++ "b/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217.png"
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6f2424caceb72a4e1582943c71e7b1abd47165708f2f1d88cea79daabe54a081
+size 2434229
diff --git "a/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217D.png" "b/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217D.png"
new file mode 100644
index 0000000000000000000000000000000000000000..4e13ae7d7fb8973775e25a8a06a010e82a5d1e22
--- /dev/null
+++ "b/Yunzai/plugins/TRSS-Plugin/Picture/\350\213\217\345\215\212\345\244\217D.png"
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5998d6bb901e9b5b953365cecb2cd6c7818737a106207b2a12dc538c2593ca02
+size 1734685
diff --git a/Yunzai/plugins/TRSS-Plugin/README.md b/Yunzai/plugins/TRSS-Plugin/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..28979b4034d5340048e0e9a358f8050151876a09
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/README.md
@@ -0,0 +1,278 @@
+
+
+
+
+
+
+
+
+
+# TRSS Yunzai Plugin
+
+云崽机器人插件
+
+[](https://github.com/TimeRainStarSky/TRSS-Plugin)
+[](../../stargazers)
+[](Install.sh)
+[](../../releases/latest)
+
+[](https://github.com/TimeRainStarSky/TRSS-Plugin)
+
+
+
+## 安装教程
+
+- 推荐使用 [TRSS Yunzai 管理脚本](https://TRSS.me) 安装
+
+[](../../../TRSS_Yunzai)
+
+1. 准备:[Yunzai-Bot](https://github.com/Le-niao/Yunzai-Bot)
+
+2. 安装:[GitHub](https://github.com/TimeRainStarSky/TRSS-Plugin) 或 [Gitee](https://gitee.com/TimeRainStarSky/TRSS-Plugin)
+
+```
+git clone --depth 1 https://Yunzai.TRSS.me plugins/TRSS-Plugin
+pnpm i
+```
+
+3. 安装 `图片修复` | `图片背景去除` | `语音合成`,不用可忽略
+
+展开
+
+安装 [Python 3.10-3.11](https://python.org) 和 [Poetry](https://python-poetry.org),并在插件目录执行以下操作
+
+```
+poetry install
+```
+
+- 图片修复:
+
+```
+git clone --depth 1 https://gitee.com/TimeRainStarSky/Real-ESRGAN
+cd Real-ESRGAN
+poetry run python setup.py develop
+```
+
+- 图片背景去除:
+
+```
+git clone --depth 1 https://gitee.com/TimeRainStarSky/RemBG
+cd RemBG
+curl -LO https://github.com/TimeRainStarSky/TRSS-Plugin/releases/download/latest/u2net.onnx.xz
+curl -LO https://github.com/TimeRainStarSky/TRSS-Plugin/releases/download/latest/isnetis.onnx.xz
+xz -dv u2net.onnx.xz isnetis.onnx.xz
+```
+
+- 语音合成:
+
+```
+poetry run pip install monotonic-align
+git clone --depth 1 https://gitee.com/TimeRainStarSky/ChatWaifu
+git clone --depth 1 https://gitee.com/TimeRainStarSky/GenshinVoice
+```
+
+- 语音合成 汉语模型:
+
+```
+cd ChatWaifu
+curl -LO https://github.com/TimeRainStarSky/TRSS-Plugin/releases/download/latest/ChatWaifuCN.txz
+tar -xvJf ChatWaifuCN.txz
+```
+
+- 语音合成 日语模型:
+
+```
+cd ChatWaifu
+curl -LO https://github.com/TimeRainStarSky/TRSS-Plugin/releases/download/latest/ChatWaifuJP.txz
+tar -xvJf ChatWaifuJP.txz
+```
+
+- 语音合成 原神模型:
+```
+cd GenshinVoice
+curl -LO https://github.com/TimeRainStarSky/TRSS-Plugin/releases/download/latest/G_809000.pth.xz
+xz -dv G_809000.pth.xz
+```
+
+部署为 API 服务器
+
+```
+bash server.sh [端口]
+```
+
+
+
+- 阿里云盘 / 百度网盘:
+
+使用脚本安装后,启动 CLI,输入 `login -h`,按提示登录
+
+
+
+## 使用教程
+
+图片修复
+
+- 图片修复 / 动漫图片修复 + `图片`
+
+
+
+图片背景去除
+
+- 图片背景去除 / 动漫图片背景去除 + `图片`
+
+
+
+语音合成
+
+- `角色名` + (转码)?说 + `中文`
+- 语音合成角色列表
+
+
+
+系统信息
+
+- 系统信息 / 系统信息图片 / 系统测试
+
+
+
+二维码生成
+
+- 二维码 + `文字`
+
+
+
+米哈游登录
+
+- 二维码登录:米哈游登录
+- 账号密码登录:米哈游登录 + `账号`
+
+
+
+Markdown(权限:主人)
+
+- md + `文件` / `URL`
+
+
+
+代码高亮(权限:主人)
+
+- sc + `文件` / `URL`
+
+
+
+远程命令(权限:主人)
+
+- rc / rcp / rcj / rcjp + `命令`
+
+
+
+文件操作(权限:主人)
+
+- 文件查看 / 文件上传 / 文件下载 + `路径`
+
+
+
+阿里云盘(权限:主人)
+
+阿里云盘 +
+
+- 帮助
+- 上传
+- 下载
+- 相簿
+- 链接
+- 查看
+- 创建目录
+- 移动
+- 回收站
+- 重命名
+- 删除
+- 分享
+- 同步备份
+- 树形图
+- 在线网盘
+- 切换网盘
+- 登录账号
+- 账号列表
+- 退出账号
+- 空间配额
+- 切换账号
+- 当前账号
+
+
+
+百度网盘(权限:主人)
+
+百度网盘 +
+
+- 帮助
+- 上传
+- 下载
+- 复制
+- 链接
+- 查看
+- 元信息
+- 创建目录
+- 移动
+- 离线下载
+- 空间配额
+- 回收站
+- 删除
+- 搜索
+- 分享
+- 转存
+- 树形图
+- 登录账号
+- 账号列表
+- 退出账号
+- 切换账号
+- 当前账号
+
+
+
+## 常见问题
+
+展开
+
+- 问:`ModuleNotFoundError: No module named 'xxx'`
+- 答:未正确执行 `poetry install`
+
+- 问:`已杀死` | `Signal 9` | `MemoryError`
+- 答:`清理内存` 或 `增加 SWAP`
+
+- 问:使用 `Git Bash` 执行 `poetry install` 失败
+- 答:改用 `命令提示符` 或 `Windows PowerShell`
+
+- 问:`error: Microsoft Visual C++ 14.0 or greater is required.`
+- 答:下载安装 [Microsoft C++ 生成工具](https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools)
+
+
+- 问:`'bash' 不是内部或外部命令,也不是可运行的程序或批处理文件` `bash : 无法将“sh”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。`
+- 答:改用 `Git Bash`
+
+- 问:手动安装过程中出现问题
+- 答:建议自行解决,不会就用脚本一键安装
+
+- 问:我有其他问题
+- 答:提供详细问题描述,通过下方 联系方式 反馈问题
+
+
+
+## 联系方式
+
+- QQ 群组:
+1. [659945190](https://jq.qq.com/?k=VBuHGPv3)
+2. [1027131254](https://jq.qq.com/?k=Af0pTDHU)
+3. [300714227](https://jq.qq.com/?k=V2xVpaR7)
+
+### 时雨 🌌 星空
+
+- GitHub:[TimeRainStarSky](https://github.com/TimeRainStarSky)
+- 酷安:[时雨丶星空](https://coolapk.com/u/2650948)
+- QQ:[2536554304](https://qm.qq.com/cgi-bin/qm/qr?k=x8LtlP8vwZs7qLwmsbCsyLoAHy7Et1Pj)
+- Telegram:[TimeRainStarSky](https://t.me/TimeRainStarSky)
+
+## 赞助支持
+
+- 爱发电:
+- Partme:
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.css b/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.css
new file mode 100644
index 0000000000000000000000000000000000000000..0ab9feebd808e45b0af34fb82fb5765488c21a18
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.css
@@ -0,0 +1,20 @@
+@font-face {
+ font-family: InconsolataGo;
+ src: url("../fonts/InconsolataGo.ttf");
+}
+body {
+ background: url("https://api.gmit.vip/Api/DmImg?format=image") white center top no-repeat;
+ background-size: cover;
+ padding: 10px 20px;
+}
+.box {
+ padding: 10px;
+ background: rgba(255, 255, 255, 0.45);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ backdrop-filter: blur(6px);
+ -webkit-backdrop-filter: blur(6px);
+ border-radius: 10px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ white-space: pre-wrap;
+ font-family: InconsolataGo, monospace;
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.html b/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.html
new file mode 100644
index 0000000000000000000000000000000000000000..5ef3e1855083307a437bc08fe70601e18034640c
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/Code/Code.html
@@ -0,0 +1,10 @@
+
+
+
+
+ 代码展示框
+
+{{@Code}}
+
+ TRSS-Plugin
+
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.css b/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.css
new file mode 100644
index 0000000000000000000000000000000000000000..0e3c54832445c91ca51f54f738f133f807752493
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.css
@@ -0,0 +1,18 @@
+@font-face {
+ font-family: InconsolataGo;
+ src: url("../fonts/InconsolataGo.ttf");
+}
+body {
+ background: url("https://api.gmit.vip/Api/DmImg?format=image") white center top no-repeat;
+ background-size: cover;
+ padding: 10px 20px;
+}
+.box {
+ padding: 10px;
+ background: rgba(255, 255, 255, 0.45);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ backdrop-filter: blur(6px);
+ -webkit-backdrop-filter: blur(6px);
+ border-radius: 10px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.html b/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.html
new file mode 100644
index 0000000000000000000000000000000000000000..24c92a6511dc7f2690925ed7ee5133729aab0619
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/Markdown/Markdown.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+ Markdown 展示框
+
+
+ {{@Markdown}}
+
+
+ TRSS-Plugin
+
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.css b/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.css
new file mode 100644
index 0000000000000000000000000000000000000000..0e3c54832445c91ca51f54f738f133f807752493
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.css
@@ -0,0 +1,18 @@
+@font-face {
+ font-family: InconsolataGo;
+ src: url("../fonts/InconsolataGo.ttf");
+}
+body {
+ background: url("https://api.gmit.vip/Api/DmImg?format=image") white center top no-repeat;
+ background-size: cover;
+ padding: 10px 20px;
+}
+.box {
+ padding: 10px;
+ background: rgba(255, 255, 255, 0.45);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ backdrop-filter: blur(6px);
+ -webkit-backdrop-filter: blur(6px);
+ border-radius: 10px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.html b/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.html
new file mode 100644
index 0000000000000000000000000000000000000000..7ac219c980d78b2771af132510d2b5ed0f32f487
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/Resources/SourceCode/SourceCode.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+ 源码展示框
+
+
+
+ TRSS-Plugin
+
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/Resources/fonts/InconsolataGo.ttf b/Yunzai/plugins/TRSS-Plugin/Resources/fonts/InconsolataGo.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..8564b3d783b525c295cd16dc5801286f1c0dc08c
Binary files /dev/null and b/Yunzai/plugins/TRSS-Plugin/Resources/fonts/InconsolataGo.ttf differ
diff --git a/Yunzai/plugins/TRSS-Plugin/index.js b/Yunzai/plugins/TRSS-Plugin/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..dbf60e388d5ff9f56d7e432348405a523c46e5ee
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/index.js
@@ -0,0 +1,56 @@
+logger.info(logger.yellow("- 正在加载 TRSS 插件"))
+
+import fs from "node:fs"
+import util from "node:util"
+import QR from "qrcode"
+import config from "./Model/config.js"
+import common from "../../lib/common/common.js"
+import puppeteer from "../../lib/puppeteer/puppeteer.js"
+import { exec } from "child_process"
+import MarkdownIt from "markdown-it"
+import { AnsiUp } from "ansi_up"
+
+global.fs = fs
+global.util = util
+global.QR = QR
+global.config = config
+global.common = common
+global.puppeteer = puppeteer
+global.exec = exec
+global.md = new MarkdownIt
+global.ansi_up = new AnsiUp
+
+if (!global.segment) {
+ logger.warn(logger.red("! 未找到 segment,建议更新 Yunzai"))
+ global.segment = (await import("oicq")).segment
+}
+
+try {
+ global.uploadRecord = (await import("./Model/uploadRecord.js")).default
+} catch (err) {
+ global.uploadRecord = segment.record
+}
+
+const files = fs
+ .readdirSync("plugins/TRSS-Plugin/Apps")
+ .filter((file) => file.endsWith(".js"))
+
+let ret = []
+files.forEach((file) => {
+ ret.push(import(`./Apps/${file}`))
+})
+ret = await Promise.allSettled(ret)
+
+const apps = {}
+for (const i in files) {
+ const name = files[i].replace(".js", "")
+ if (ret[i].status != "fulfilled") {
+ logger.error("载入插件错误:" + logger.red(name))
+ logger.error(ret[i].reason)
+ continue
+ }
+ apps[name] = ret[i].value[name]
+}
+export { apps }
+
+logger.info(logger.green("- TRSS 插件 加载完成"))
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it
new file mode 100644
index 0000000000000000000000000000000000000000..6c96fb6078777a689d952700688f14c5a678a17e
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it
@@ -0,0 +1,17 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -z "$NODE_PATH" ]; then
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+else
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules:$NODE_PATH"
+fi
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" "$@"
+else
+ exec node "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" "$@"
+fi
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.CMD b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.CMD
new file mode 100644
index 0000000000000000000000000000000000000000..fad51a57a8749ac7ada99a24175c5b54de939e8e
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.CMD
@@ -0,0 +1,12 @@
+@SETLOCAL
+@IF NOT DEFINED NODE_PATH (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+) ELSE (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules;%NODE_PATH%"
+)
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\..\..\..\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\bin\markdown-it.js" %*
+) ELSE (
+ @SET PATHEXT=%PATHEXT:;.JS;=;%
+ node "%~dp0\..\..\..\..\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\bin\markdown-it.js" %*
+)
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.ps1 b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..78e6388e607ac5c8a85fe85cc50a3fda00b0d5e1
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/markdown-it.ps1
@@ -0,0 +1,41 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+$pathsep=":"
+$env_node_path=$env:NODE_PATH
+$new_node_path="E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules\markdown-it\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\markdown-it@13.0.1\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+ $pathsep=";"
+} else {
+ $new_node_path="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/markdown-it@13.0.1/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+}
+if ([string]::IsNullOrEmpty($env_node_path)) {
+ $env:NODE_PATH=$new_node_path
+} else {
+ $env:NODE_PATH="$new_node_path$pathsep$env_node_path"
+}
+
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" $args
+ } else {
+ & "node$exe" "$basedir/../../../../node_modules/.pnpm/markdown-it@13.0.1/node_modules/markdown-it/bin/markdown-it.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+$env:NODE_PATH=$env_node_path
+exit $ret
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode
new file mode 100644
index 0000000000000000000000000000000000000000..654c09a23fc5323b42d9303509a2fa320404ac38
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode
@@ -0,0 +1,17 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -z "$NODE_PATH" ]; then
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+else
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules:$NODE_PATH"
+fi
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" "$@"
+else
+ exec node "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" "$@"
+fi
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.CMD b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.CMD
new file mode 100644
index 0000000000000000000000000000000000000000..ad8c2a1ffd8db26cd3a46afe28a695484aa8de45
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.CMD
@@ -0,0 +1,12 @@
+@SETLOCAL
+@IF NOT DEFINED NODE_PATH (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+) ELSE (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules;%NODE_PATH%"
+)
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\..\..\..\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\qrcode" %*
+) ELSE (
+ @SET PATHEXT=%PATHEXT:;.JS;=;%
+ node "%~dp0\..\..\..\..\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\qrcode" %*
+)
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.ps1 b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..6c9152ff5442f6b7f6cdfe27ee85260ace1d703d
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/.bin/qrcode.ps1
@@ -0,0 +1,41 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+$pathsep=":"
+$env_node_path=$env:NODE_PATH
+$new_node_path="E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+ $pathsep=";"
+} else {
+ $new_node_path="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+}
+if ([string]::IsNullOrEmpty($env_node_path)) {
+ $env:NODE_PATH=$new_node_path
+} else {
+ $env:NODE_PATH="$new_node_path$pathsep$env_node_path"
+}
+
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" $args
+ } else {
+ & "node$exe" "$basedir/../../../../node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/qrcode" $args
+ }
+ $ret=$LASTEXITCODE
+}
+$env:NODE_PATH=$env_node_path
+exit $ret
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/.notags b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/.notags
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/LICENSE b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..6bf63c2437bc02c7f575bc9043399db118dcaafe
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2011 Dru Nelson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Makefile b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..dc5e01bb9b5bca36a1b14e8ab26c6e6a8c573222
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Makefile
@@ -0,0 +1,24 @@
+
+SOURCE = *.ts
+TESTS = test/*.js
+REPORTER = dot
+
+typescript:
+ ./node_modules/.bin/tsc -p .
+
+test:
+ @NODE_ENV=test ./node_modules/.bin/mocha \
+ --require should \
+ --reporter $(REPORTER) \
+ $(TESTS)
+
+test_verbose:
+ @NODE_ENV=test ./node_modules/.bin/mocha \
+ --require should \
+ --reporter spec \
+ $(TESTS)
+
+clean:
+ rm -rf ./node_modules ansi_up.js
+
+.PHONY: test
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Readme.md b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..c0409a94e53f35f59551f94a38960196ebd5c872
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/Readme.md
@@ -0,0 +1,205 @@
+# ansi_up.js
+
+__ansi_up__ is an easy to use library that transforms text containing
+[ANSI color escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) into HTML.
+
+This module is a single ES6 Javascript file with no dependencies.
+It is "isomorphic" javascript. This is just another way of saying that
+the ansi_up.js file will work in both the browser or node.js.
+The js library is compiled from TypeScript and its type description ships with the NPM.
+This code has been used in production since 2011 and is actively maintained.
+
+For example, turn this terminal output:
+
+ ESC[1;Foreground
+ [1;30m 30 [1;30m 30 [1;30m 30 [1;30m 30 [1;30m 30 [1;30m 30 [1;30m 30 [1;30m 30 [0m
+ [1;31m 31 [1;31m 31 [1;31m 31 [1;31m 31 [1;31m 31 [1;31m 31 [1;31m 31 [1;31m 31 [0m
+ [1;32m 32 [1;32m 32 [1;32m 32 [1;32m 32 [1;32m 32 [1;32m 32 [1;32m 32 [1;32m 32 [0m
+ ...
+
+...into this browser output:
+
+
+
+
+## Browser Example
+
+```HTML
+
+
+```
+
+## Node Example
+
+```JavaScript
+ import { AnsiUp } from './ansi_up.js'
+ var ansi_up = new AnsiUp();
+
+ var txt = "\n\n\033[1;33;40m 33;40 \033[1;33;41m 33;41 \033[1;33;42m 33;42 \033[1;33;43m 33;43 \033[1;33;44m 33;44 \033[1;33;45m 33;45 \033[1;33;46m 33;46 \033[1m\033[0\n\n\033[1;33;42m >> Tests OK\n\n"
+
+ var html = ansi_up.ansi_to_html(txt);
+```
+
+More examples are in the 'examples' directory in the repo.
+
+## Typescript Example
+
+```TypeScript
+ import { AnsiUp } from './ansi_up.js'
+ const ansi_up = new AnsiUp();
+
+ const txt = "\n\n\x1B[1;33;40m 33;40 \x1B[1;33;41m 33;41 \x1B[1;33;42m 33;42 \x1B[1;33;43m 33;43 \x1B[1;33;44m 33;44 \x1B[1;33;45m 33;45 \x1B[1;33;46m 33;46 \x1B[1m\x1B[0\n\n\x1B[1;33;42m >> Tests OK\n\n"
+
+ let html = ansi_up.ansi_to_html(txt);
+```
+
+## Installation
+
+ $ npm install ansi_up
+
+## Versions
+* Version 6.0 - Switch to ES6 module. Add faint styles. Style css configurable.
+* Version 5.1 - Add italic and underline styles (@DaoDaoNoCode)
+* Version 5.0 - Security fix for OSC URLs
+* Version 4.0 - Re-architect code to support [terminal URL codes](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
+* Version 3.0 - now treats ANSI bold sequences as CSS font-weight:bold
+* Version 2.0 - moved to a stateful, streaming version of the API
+* Version 1.3 - was the last of the older, deprecated API.
+
+## Quick Start
+
+1. Use whatever module system to import the _ansi_up_ module.
+2. Instantiate the object.
+3. For every piece of ansi escaped text string, call **ansi_to_html**.
+4. Append the emitted HTML to the previous HTML already emitted.
+5. DONE
+
+
+## API Methods and Recommended Settings
+
+You only need the ansi_to_html method. The other properties listed below allow you to
+override some of the escaping behaviour. You probably don't need to change these
+from their default values.
+
+It is recommended that the HTML container that holds the span tags is styled with a monospace font.
+A PRE tag would work just fine for this.
+It is also recommended that the HTML container is styled with a black background.
+See the examples, for more CSS theming.
+
+
+#### ansi_to_html (txt)
+
+This transforms ANSI terminal escape codes/sequences into SPAN tags that wrap and style the content.
+
+This method only interprets ANSI SGR (Select Graphic Rendition) codes or escaped URL codes.
+For example, cursor movement codes are ignored and hidden from output.
+
+This method also safely escapes any unsafe HTML characters.
+
+The default style uses colors that are very close to the prescribed standard.
+The standard assumes that the text will have a black background.
+These colors are set as inline styles on the SPAN tags.
+Another option is to set the 'use_classes' property to true'.
+This will instead set classes on the spans so the colors can be set via CSS.
+The class names used are of the format ````ansi-*-fg/bg```` and ````ansi-bright-*-fg/bg```` where * is the colour name, i.e black/red/green/yellow/blue/magenta/cyan/white.
+See the examples directory for a complete CSS theme for these classes.
+
+## Properties
+
+#### escape_html
+(default: true)
+
+By default, HTML's reserved characters `& < > " '` are replaced with HTML entities to make them appear as literal characters in your application, rather than being interpreted as HTML structure. If you prefer keeping HTML's reserved characters untouched, you can set this to false.
+
+#### use_classes
+(default: false)
+
+This causes the SPAN tags to use classes to style the SPAN tags instead
+of specified RGB values.
+
+#### url_allowlist
+(default: { 'http':1, 'https':1 })
+
+This mapping is an 'allow' list of URI schemes that will be allowed to render HTML anchor tags.
+
+#### boldStyle
+(default: 'font-weight:bold')
+#### faintStyle
+(default: 'opacity:0.7')
+#### italicStyle
+(default: 'font-style:italic')
+#### underlineStyle
+(default: 'text-decoration:underline')
+
+## Buffering
+
+In general, the ansi_to_html *should* emit HTML output when invoked with a non-empty string.
+The only exceptions are an incomplete ESC sequence or an incomplete OSC URL sequence.
+For those cases, the library will buffer (not emit output), until it receives input that completes those sequences.
+
+### Example of a Use Case
+
+I have used this library to 'tail' a file.
+
+On a remote machine, I had process generating a log file.
+I had a web server running on the same machine.
+The server hosted a simple HTML page that used AJAX to poll an object with a range query.
+Specifically I used an HTTP/1.1 GET request with RFC 7233 Range query.
+The first range query would start at 0, but then progressively move forward after
+new data was received.
+
+For each new chunk of data received, I would transform the data with _ansi_up_, and append the new
+spans to the innerHTML of a PRE tag.
+
+
+### UTF8 note
+
+One last important note, _ansi_up_ takes its input in the form of a Javascript string.
+These strings are UTF8. When you take the output of some program and send it to
+Javascript, there will be buffering. Be sure that you do not send incomplete UTF8 sequences.
+Javascript will ignore or drop the sequence from the stream when it converts it to a
+string.
+
+
+## Building
+
+To build, a simple Makefile handles it all.
+
+```shell
+ $ make
+```
+
+## Running tests
+
+To run the tests for _ansi_up_, run `npm install` to install dev dependencies. Then:
+
+```shell
+ $ make test
+```
+
+## Credits
+
+This code was developed by Dru Nelson ().
+
+Thanks goes to the following contributors for their patches:
+
+- Juntao Wang ()
+- AIZAWA Hina ()
+- James R. White ()
+- Aaron Stone ()
+- Maximilian Antoni ()
+- Jim Bauwens ()
+- Jacek Jędrzejewski ()
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.d.ts b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..28f06c6b5f4e0c9192af8ad6a13d5b68f577d39b
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.d.ts
@@ -0,0 +1,46 @@
+export declare class AnsiUp {
+ VERSION: string;
+ private ansi_colors;
+ private palette_256;
+ private fg;
+ private bg;
+ private bold;
+ private faint;
+ private italic;
+ private underline;
+ private _use_classes;
+ private _csi_regex;
+ private _osc_st;
+ private _osc_regex;
+ private _url_allowlist;
+ private _escape_html;
+ private _buffer;
+ private _boldStyle;
+ private _faintStyle;
+ private _italicStyle;
+ private _underlineStyle;
+ constructor();
+ set use_classes(arg: boolean);
+ get use_classes(): boolean;
+ set url_allowlist(arg: {});
+ get url_allowlist(): {};
+ set escape_html(arg: boolean);
+ get escape_html(): boolean;
+ set boldStyle(arg: string);
+ get boldStyle(): string;
+ set faintStyle(arg: string);
+ get faintStyle(): string;
+ set italicStyle(arg: string);
+ get italicStyle(): string;
+ set underlineStyle(arg: string);
+ get underlineStyle(): string;
+ private setup_palettes;
+ private escape_txt_for_html;
+ private append_buffer;
+ private get_next_packet;
+ ansi_to_html(txt: string): string;
+ private with_state;
+ private process_ansi;
+ private transform_to_html;
+ private process_hyperlink;
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cca56d7e75225f5535b42a6018b14dbec3a017c
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js
@@ -0,0 +1,431 @@
+"use strict";
+var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
+ return cooked;
+};
+var PacketKind;
+(function (PacketKind) {
+ PacketKind[PacketKind["EOS"] = 0] = "EOS";
+ PacketKind[PacketKind["Text"] = 1] = "Text";
+ PacketKind[PacketKind["Incomplete"] = 2] = "Incomplete";
+ PacketKind[PacketKind["ESC"] = 3] = "ESC";
+ PacketKind[PacketKind["Unknown"] = 4] = "Unknown";
+ PacketKind[PacketKind["SGR"] = 5] = "SGR";
+ PacketKind[PacketKind["OSCURL"] = 6] = "OSCURL";
+})(PacketKind || (PacketKind = {}));
+export class AnsiUp {
+ constructor() {
+ this.VERSION = "6.0.2";
+ this.setup_palettes();
+ this._use_classes = false;
+ this.bold = false;
+ this.faint = false;
+ this.italic = false;
+ this.underline = false;
+ this.fg = this.bg = null;
+ this._buffer = '';
+ this._url_allowlist = { 'http': 1, 'https': 1 };
+ this._escape_html = true;
+ this.boldStyle = 'font-weight:bold';
+ this.faintStyle = 'opacity:0.7';
+ this.italicStyle = 'font-style:italic';
+ this.underlineStyle = 'text-decoration:underline';
+ }
+ set use_classes(arg) {
+ this._use_classes = arg;
+ }
+ get use_classes() {
+ return this._use_classes;
+ }
+ set url_allowlist(arg) {
+ this._url_allowlist = arg;
+ }
+ get url_allowlist() {
+ return this._url_allowlist;
+ }
+ set escape_html(arg) {
+ this._escape_html = arg;
+ }
+ get escape_html() {
+ return this._escape_html;
+ }
+ set boldStyle(arg) { this._boldStyle = arg; }
+ get boldStyle() { return this._boldStyle; }
+ set faintStyle(arg) { this._faintStyle = arg; }
+ get faintStyle() { return this._faintStyle; }
+ set italicStyle(arg) { this._italicStyle = arg; }
+ get italicStyle() { return this._italicStyle; }
+ set underlineStyle(arg) { this._underlineStyle = arg; }
+ get underlineStyle() { return this._underlineStyle; }
+ setup_palettes() {
+ this.ansi_colors =
+ [
+ [
+ { rgb: [0, 0, 0], class_name: "ansi-black" },
+ { rgb: [187, 0, 0], class_name: "ansi-red" },
+ { rgb: [0, 187, 0], class_name: "ansi-green" },
+ { rgb: [187, 187, 0], class_name: "ansi-yellow" },
+ { rgb: [0, 0, 187], class_name: "ansi-blue" },
+ { rgb: [187, 0, 187], class_name: "ansi-magenta" },
+ { rgb: [0, 187, 187], class_name: "ansi-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-white" }
+ ],
+ [
+ { rgb: [85, 85, 85], class_name: "ansi-bright-black" },
+ { rgb: [255, 85, 85], class_name: "ansi-bright-red" },
+ { rgb: [0, 255, 0], class_name: "ansi-bright-green" },
+ { rgb: [255, 255, 85], class_name: "ansi-bright-yellow" },
+ { rgb: [85, 85, 255], class_name: "ansi-bright-blue" },
+ { rgb: [255, 85, 255], class_name: "ansi-bright-magenta" },
+ { rgb: [85, 255, 255], class_name: "ansi-bright-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-bright-white" }
+ ]
+ ];
+ this.palette_256 = [];
+ this.ansi_colors.forEach(palette => {
+ palette.forEach(rec => {
+ this.palette_256.push(rec);
+ });
+ });
+ let levels = [0, 95, 135, 175, 215, 255];
+ for (let r = 0; r < 6; ++r) {
+ for (let g = 0; g < 6; ++g) {
+ for (let b = 0; b < 6; ++b) {
+ let col = { rgb: [levels[r], levels[g], levels[b]], class_name: 'truecolor' };
+ this.palette_256.push(col);
+ }
+ }
+ }
+ let grey_level = 8;
+ for (let i = 0; i < 24; ++i, grey_level += 10) {
+ let gry = { rgb: [grey_level, grey_level, grey_level], class_name: 'truecolor' };
+ this.palette_256.push(gry);
+ }
+ }
+ escape_txt_for_html(txt) {
+ if (!this._escape_html)
+ return txt;
+ return txt.replace(/[&<>"']/gm, (str) => {
+ if (str === "&")
+ return "&";
+ if (str === "<")
+ return "<";
+ if (str === ">")
+ return ">";
+ if (str === "\"")
+ return """;
+ if (str === "'")
+ return "'";
+ });
+ }
+ append_buffer(txt) {
+ var str = this._buffer + txt;
+ this._buffer = str;
+ }
+ get_next_packet() {
+ var pkt = {
+ kind: PacketKind.EOS,
+ text: '',
+ url: ''
+ };
+ var len = this._buffer.length;
+ if (len == 0)
+ return pkt;
+ var pos = this._buffer.indexOf("\x1B");
+ if (pos == -1) {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer;
+ this._buffer = '';
+ return pkt;
+ }
+ if (pos > 0) {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer.slice(0, pos);
+ this._buffer = this._buffer.slice(pos);
+ return pkt;
+ }
+ if (pos == 0) {
+ if (len < 3) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ var next_char = this._buffer.charAt(1);
+ if ((next_char != '[') && (next_char != ']') && (next_char != '(')) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if (next_char == '[') {
+ if (!this._csi_regex) {
+ this._csi_regex = rgx(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \u001B[ # CSI\n ([<-?]?) # private-mode char\n ([d;]*) # any digits or semicolons\n ([ -/]? # an intermediate modifier\n [@-~]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \u001B[ # CSI\n [ -~]* # anything legal\n ([\0-\u001F:]) # anything illegal\n )\n "], ["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \\x1b\\[ # CSI\n ([\\x3c-\\x3f]?) # private-mode char\n ([\\d;]*) # any digits or semicolons\n ([\\x20-\\x2f]? # an intermediate modifier\n [\\x40-\\x7e]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \\x1b\\[ # CSI\n [\\x20-\\x7e]* # anything legal\n ([\\x00-\\x1f:]) # anything illegal\n )\n "])));
+ }
+ let match = this._buffer.match(this._csi_regex);
+ if (match === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match[4]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if ((match[1] != '') || (match[3] != 'm'))
+ pkt.kind = PacketKind.Unknown;
+ else
+ pkt.kind = PacketKind.SGR;
+ pkt.text = match[2];
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ else if (next_char == ']') {
+ if (len < 4) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if ((this._buffer.charAt(2) != '8')
+ || (this._buffer.charAt(3) != ';')) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ if (!this._osc_st) {
+ this._osc_st = rgxG(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n (?: # legal sequence\n (\u001B\\) # ESC | # alternate\n (\u0007) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\0-\u0006] # anything illegal\n | # alternate\n [\b-\u001A] # anything illegal\n | # alternate\n [\u001C-\u001F] # anything illegal\n )\n "], ["\n (?: # legal sequence\n (\\x1b\\\\) # ESC \\\n | # alternate\n (\\x07) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\\x00-\\x06] # anything illegal\n | # alternate\n [\\x08-\\x1a] # anything illegal\n | # alternate\n [\\x1c-\\x1f] # anything illegal\n )\n "])));
+ }
+ this._osc_st.lastIndex = 0;
+ {
+ let match = this._osc_st.exec(this._buffer);
+ if (match === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match[3]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+ {
+ let match = this._osc_st.exec(this._buffer);
+ if (match === null) {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+ if (match[3]) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+ if (!this._osc_regex) {
+ this._osc_regex = rgx(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n ^ # beginning of line\n #\n \u001B]8; # OSC Hyperlink\n [ -:<-~]* # params (excluding ;)\n ; # end of params\n ([!-~]{0,512}) # URL capture\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n ([ -~]+) # TEXT capture\n \u001B]8;; # OSC Hyperlink End\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n "], ["\n ^ # beginning of line\n #\n \\x1b\\]8; # OSC Hyperlink\n [\\x20-\\x3a\\x3c-\\x7e]* # params (excluding ;)\n ; # end of params\n ([\\x21-\\x7e]{0,512}) # URL capture\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n ([\\x20-\\x7e]+) # TEXT capture\n \\x1b\\]8;; # OSC Hyperlink End\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n "])));
+ }
+ let match = this._buffer.match(this._osc_regex);
+ if (match === null) {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ pkt.kind = PacketKind.OSCURL;
+ pkt.url = match[1];
+ pkt.text = match[2];
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ else if (next_char == '(') {
+ pkt.kind = PacketKind.Unknown;
+ this._buffer = this._buffer.slice(3);
+ return pkt;
+ }
+ }
+ }
+ ansi_to_html(txt) {
+ this.append_buffer(txt);
+ var blocks = [];
+ while (true) {
+ var packet = this.get_next_packet();
+ if ((packet.kind == PacketKind.EOS)
+ || (packet.kind == PacketKind.Incomplete))
+ break;
+ if ((packet.kind == PacketKind.ESC)
+ || (packet.kind == PacketKind.Unknown))
+ continue;
+ if (packet.kind == PacketKind.Text)
+ blocks.push(this.transform_to_html(this.with_state(packet)));
+ else if (packet.kind == PacketKind.SGR)
+ this.process_ansi(packet);
+ else if (packet.kind == PacketKind.OSCURL)
+ blocks.push(this.process_hyperlink(packet));
+ }
+ return blocks.join("");
+ }
+ with_state(pkt) {
+ return { bold: this.bold, faint: this.faint, italic: this.italic, underline: this.underline, fg: this.fg, bg: this.bg, text: pkt.text };
+ }
+ process_ansi(pkt) {
+ let sgr_cmds = pkt.text.split(';');
+ while (sgr_cmds.length > 0) {
+ let sgr_cmd_str = sgr_cmds.shift();
+ let num = parseInt(sgr_cmd_str, 10);
+ if (isNaN(num) || num === 0) {
+ this.fg = null;
+ this.bg = null;
+ this.bold = false;
+ this.faint = false;
+ this.italic = false;
+ this.underline = false;
+ }
+ else if (num === 1) {
+ this.bold = true;
+ }
+ else if (num === 2) {
+ this.faint = true;
+ }
+ else if (num === 3) {
+ this.italic = true;
+ }
+ else if (num === 4) {
+ this.underline = true;
+ }
+ else if (num === 21) {
+ this.bold = false;
+ }
+ else if (num === 22) {
+ this.faint = false;
+ this.bold = false;
+ }
+ else if (num === 23) {
+ this.italic = false;
+ }
+ else if (num === 24) {
+ this.underline = false;
+ }
+ else if (num === 39) {
+ this.fg = null;
+ }
+ else if (num === 49) {
+ this.bg = null;
+ }
+ else if ((num >= 30) && (num < 38)) {
+ this.fg = this.ansi_colors[0][(num - 30)];
+ }
+ else if ((num >= 40) && (num < 48)) {
+ this.bg = this.ansi_colors[0][(num - 40)];
+ }
+ else if ((num >= 90) && (num < 98)) {
+ this.fg = this.ansi_colors[1][(num - 90)];
+ }
+ else if ((num >= 100) && (num < 108)) {
+ this.bg = this.ansi_colors[1][(num - 100)];
+ }
+ else if (num === 38 || num === 48) {
+ if (sgr_cmds.length > 0) {
+ let is_foreground = (num === 38);
+ let mode_cmd = sgr_cmds.shift();
+ if (mode_cmd === '5' && sgr_cmds.length > 0) {
+ let palette_index = parseInt(sgr_cmds.shift(), 10);
+ if (palette_index >= 0 && palette_index <= 255) {
+ if (is_foreground)
+ this.fg = this.palette_256[palette_index];
+ else
+ this.bg = this.palette_256[palette_index];
+ }
+ }
+ if (mode_cmd === '2' && sgr_cmds.length > 2) {
+ let r = parseInt(sgr_cmds.shift(), 10);
+ let g = parseInt(sgr_cmds.shift(), 10);
+ let b = parseInt(sgr_cmds.shift(), 10);
+ if ((r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255)) {
+ let c = { rgb: [r, g, b], class_name: 'truecolor' };
+ if (is_foreground)
+ this.fg = c;
+ else
+ this.bg = c;
+ }
+ }
+ }
+ }
+ }
+ }
+ transform_to_html(fragment) {
+ let txt = fragment.text;
+ if (txt.length === 0)
+ return txt;
+ txt = this.escape_txt_for_html(txt);
+ if (!fragment.bold && !fragment.italic && !fragment.underline && fragment.fg === null && fragment.bg === null)
+ return txt;
+ let styles = [];
+ let classes = [];
+ let fg = fragment.fg;
+ let bg = fragment.bg;
+ if (fragment.bold)
+ styles.push(this._boldStyle);
+ if (fragment.faint)
+ styles.push(this._faintStyle);
+ if (fragment.italic)
+ styles.push(this._italicStyle);
+ if (fragment.underline)
+ styles.push(this._underlineStyle);
+ if (!this._use_classes) {
+ if (fg)
+ styles.push(`color:rgb(${fg.rgb.join(',')})`);
+ if (bg)
+ styles.push(`background-color:rgb(${bg.rgb})`);
+ }
+ else {
+ if (fg) {
+ if (fg.class_name !== 'truecolor') {
+ classes.push(`${fg.class_name}-fg`);
+ }
+ else {
+ styles.push(`color:rgb(${fg.rgb.join(',')})`);
+ }
+ }
+ if (bg) {
+ if (bg.class_name !== 'truecolor') {
+ classes.push(`${bg.class_name}-bg`);
+ }
+ else {
+ styles.push(`background-color:rgb(${bg.rgb.join(',')})`);
+ }
+ }
+ }
+ let class_string = '';
+ let style_string = '';
+ if (classes.length)
+ class_string = ` class="${classes.join(' ')}"`;
+ if (styles.length)
+ style_string = ` style="${styles.join(';')}"`;
+ return `${txt}`;
+ }
+ ;
+ process_hyperlink(pkt) {
+ let parts = pkt.url.split(':');
+ if (parts.length < 1)
+ return '';
+ if (!this._url_allowlist[parts[0]])
+ return '';
+ let result = `${this.escape_txt_for_html(pkt.text)}`;
+ return result;
+ }
+}
+function rgx(tmplObj, ...subst) {
+ let regexText = tmplObj.raw[0];
+ let wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ let txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2);
+}
+function rgxG(tmplObj, ...subst) {
+ let regexText = tmplObj.raw[0];
+ let wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ let txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2, 'g');
+}
+var templateObject_1, templateObject_2, templateObject_3;
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js.map b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..d42006ebb880c4bb06393669b4afc0c43dabc24e
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ansi_up.js","sourceRoot":"","sources":["ansi_up.ts"],"names":[],"mappings":"AAMA,YAAY,CAAC;;;;;AA0Bb,IAAK,UAQJ;AARD,WAAK,UAAU;IACX,yCAAG,CAAA;IACH,2CAAI,CAAA;IACJ,uDAAU,CAAA;IACV,yCAAG,CAAA;IACH,iDAAO,CAAA;IACP,yCAAG,CAAA;IACH,+CAAM,CAAA;AACV,CAAC,EARI,UAAU,KAAV,UAAU,QAQd;AAYD,MAAM,OAAO,MAAM;IA8Bf;QA5BA,YAAO,GAAG,OAAO,CAAC;QA+Bd,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAE1B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QAEzB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAElB,IAAI,CAAC,cAAc,GAAG,EAAE,MAAM,EAAC,CAAC,EAAE,OAAO,EAAC,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,IAAI,WAAW,CAAC,GAAW;QAEvB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;IAC5B,CAAC;IAED,IAAI,WAAW;QAEX,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED,IAAI,aAAa,CAAC,GAAM;QAEpB,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;IAC9B,CAAC;IAED,IAAI,aAAa;QAEb,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAED,IAAI,WAAW,CAAC,GAAW;QAEvB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;IAC5B,CAAC;IAED,IAAI,WAAW;QAEX,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAGO,cAAc;QAElB,IAAI,CAAC,WAAW;YAChB;gBAEI;oBACI,EAAE,GAAG,EAAE,CAAG,CAAC,EAAI,CAAC,EAAI,CAAC,CAAC,EAAG,UAAU,EAAE,YAAY,EAAI;oBACrD,EAAE,GAAG,EAAE,CAAC,GAAG,EAAI,CAAC,EAAI,CAAC,CAAC,EAAG,UAAU,EAAE,UAAU,EAAM;oBACrD,EAAE,GAAG,EAAE,CAAG,CAAC,EAAE,GAAG,EAAI,CAAC,CAAC,EAAG,UAAU,EAAE,YAAY,EAAI;oBACrD,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAI,CAAC,CAAC,EAAG,UAAU,EAAE,aAAa,EAAG;oBACrD,EAAE,GAAG,EAAE,CAAG,CAAC,EAAI,CAAC,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,WAAW,EAAK;oBACrD,EAAE,GAAG,EAAE,CAAC,GAAG,EAAI,CAAC,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,cAAc,EAAE;oBACrD,EAAE,GAAG,EAAE,CAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,WAAW,EAAK;oBACrD,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,YAAY,EAAI;iBACxD;gBAGD;oBACI,EAAE,GAAG,EAAE,CAAE,EAAE,EAAG,EAAE,EAAG,EAAE,CAAC,EAAG,UAAU,EAAE,mBAAmB,EAAI;oBAC5D,EAAE,GAAG,EAAE,CAAC,GAAG,EAAG,EAAE,EAAG,EAAE,CAAC,EAAG,UAAU,EAAE,iBAAiB,EAAM;oBAC5D,EAAE,GAAG,EAAE,CAAG,CAAC,EAAE,GAAG,EAAI,CAAC,CAAC,EAAG,UAAU,EAAE,mBAAmB,EAAI;oBAC5D,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAG,EAAE,CAAC,EAAG,UAAU,EAAE,oBAAoB,EAAG;oBAC5D,EAAE,GAAG,EAAE,CAAE,EAAE,EAAG,EAAE,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,kBAAkB,EAAK;oBAC5D,EAAE,GAAG,EAAE,CAAC,GAAG,EAAG,EAAE,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,qBAAqB,EAAE;oBAC5D,EAAE,GAAG,EAAE,CAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,kBAAkB,EAAK;oBAC5D,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,UAAU,EAAE,mBAAmB,EAAI;iBAC/D;aACJ,CAAC;QAEF,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QAGtB,IAAI,CAAC,WAAW,CAAC,OAAO,CAAE,OAAO,CAAC,EAAE;YAChC,OAAO,CAAC,OAAO,CAAE,GAAG,CAAC,EAAE;gBACnB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAIH,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;YACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;gBACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;oBACxB,IAAI,GAAG,GAAG,EAAC,GAAG,EAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAC,WAAW,EAAC,CAAC;oBAC1E,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;iBAC9B;aACJ;SACJ;QAGD,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU,IAAI,EAAE,EAAE;YAC3C,IAAI,GAAG,GAAG,EAAC,GAAG,EAAC,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,UAAU,EAAC,WAAW,EAAC,CAAC;YAC7E,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAC9B;IACL,CAAC;IAEO,mBAAmB,CAAC,GAAU;QAEpC,IAAI,CAAC,IAAI,CAAC,YAAY;YAClB,OAAO,GAAG,CAAC;QACf,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;YACtC,IAAI,GAAG,KAAK,GAAG;gBAAG,OAAO,OAAO,CAAC;YACjC,IAAI,GAAG,KAAK,GAAG;gBAAG,OAAO,MAAM,CAAC;YAChC,IAAI,GAAG,KAAK,GAAG;gBAAG,OAAO,MAAM,CAAC;YAChC,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,QAAQ,CAAC;YAClC,IAAI,GAAG,KAAK,GAAG;gBAAG,OAAO,QAAQ,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,GAAU;QAE5B,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;IACvB,CAAC;IAEO,eAAe;QAEnB,IAAI,GAAG,GACH;YACI,IAAI,EAAE,UAAU,CAAC,GAAG;YACpB,IAAI,EAAE,EAAE;YACP,GAAG,EAAE,EAAE;SACX,CAAE;QAEP,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,GAAG,IAAI,CAAC;YACR,OAAO,GAAG,CAAC;QAEf,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAGvC,IAAI,GAAG,IAAI,CAAC,CAAC,EACb;YACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;YAC3B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;YACxB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;YAClB,OAAO,GAAG,CAAC;SACd;QAED,IAAI,GAAG,GAAG,CAAC,EACX;YACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;YAC3B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACtC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACvC,OAAO,GAAG,CAAC;SACd;QAGD,IAAI,GAAG,IAAI,CAAC,EACZ;YAGI,IAAI,GAAG,GAAG,CAAC,EACX;gBACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;gBACjC,OAAO,GAAG,CAAC;aACd;YAED,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAIvC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,EAClE;gBACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;gBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrC,OAAO,GAAG,CAAC;aACd;YAKD,IAAI,SAAS,IAAI,GAAG,EACpB;gBAeI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;oBAElB,IAAI,CAAC,UAAU,GAAG,GAAG,+lCAAA,kkCAiBpB,IAAA,CAAC;iBACL;gBAED,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAahD,IAAI,KAAK,KAAK,IAAI,EAClB;oBACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;oBACjC,OAAO,GAAG,CAAC;iBACd;gBASD,IAAI,KAAK,CAAC,CAAC,CAAC,EACZ;oBAEI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;oBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACrC,OAAO,GAAG,CAAC;iBACd;gBAGD,IAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;oBACtC,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;;oBAE9B,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;gBAE9B,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;gBAEnB,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACxC,OAAO,GAAG,CAAC;aACd;iBAGD,IAAI,SAAS,IAAI,GAAG,EACpB;gBACI,IAAI,GAAG,GAAG,CAAC,EACX;oBACQ,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;oBACjC,OAAO,GAAG,CAAC;iBAClB;gBAED,IAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;uBAC/B,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EACvC;oBAEI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;oBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACrC,OAAO,GAAG,CAAC;iBACd;gBA6BD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;oBAEf,IAAI,CAAC,OAAO,GAAG,IAAI,06BAAA,62BAclB,IAAA,CAAC;iBACL;gBAQD,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;gBAG3B;oBACI,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAE,IAAI,CAAC,OAAO,CAAE,CAAC;oBAE9C,IAAI,KAAK,KAAK,IAAI,EAClB;wBACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;wBACjC,OAAO,GAAG,CAAC;qBACd;oBAGD,IAAI,KAAK,CAAC,CAAC,CAAC,EACZ;wBAEI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;wBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBACrC,OAAO,GAAG,CAAC;qBACd;iBACJ;gBAQD;oBACI,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAE,IAAI,CAAC,OAAO,CAAE,CAAC;oBAE9C,IAAI,KAAK,KAAK,IAAI,EAClB;wBACI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC;wBACjC,OAAO,GAAG,CAAC;qBACd;oBAGD,IAAI,KAAK,CAAC,CAAC,CAAC,EACZ;wBAEI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;wBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBACrC,OAAO,GAAG,CAAC;qBACd;iBACJ;gBAMD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;oBAElB,IAAI,CAAC,UAAU,GAAG,GAAG,urCAAA,8pCAmBpB,IAAA,CAAC;iBACL;gBAED,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAEhD,IAAI,KAAK,KAAK,IAAI,EAClB;oBAEI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC;oBAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBACrC,OAAO,GAAG,CAAC;iBACd;gBAQD,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC;gBAC7B,GAAG,CAAC,GAAG,GAAI,KAAK,CAAC,CAAC,CAAC,CAAC;gBACpB,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAEpB,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACxC,OAAO,GAAG,CAAC;aACd;iBAGD,IAAI,SAAS,IAAI,GAAG,EACpB;gBAKI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;gBAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrC,OAAO,GAAG,CAAC;aACd;SACJ;IACL,CAAC;IAED,YAAY,CAAC,GAAU;QAEnB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAExB,IAAI,MAAM,GAAY,EAAE,CAAC;QAEzB,OAAO,IAAI,EACX;YACI,IAAI,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YAEpC,IAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC;mBAC/B,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,UAAU,CAAC;gBAC1C,MAAM;YAGV,IAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,GAAG,CAAC;mBAC/B,CAAC,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,OAAO,CAAC;gBACvC,SAAS;YAEb,IAAI,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI;gBAC9B,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;iBAEnE,IAAI,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,GAAG;gBAC7B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;iBAE9B,IAAI,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM;gBAChC,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAE,CAAC;SACrD;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAEO,UAAU,CAAC,GAAc;QAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IACzH,CAAC;IAEO,YAAY,CAAC,GAAc;QAIjC,IAAI,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAMnC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YACxB,IAAI,WAAW,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;YACnC,IAAI,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAEpC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE;gBACzB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACzB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;gBAClB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;gBACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;aAC1B;iBAAM,IAAI,GAAG,KAAK,CAAC,EAAE;gBAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;aACpB;iBAAM,IAAI,GAAG,KAAK,CAAC,EAAE;gBAClB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;aACtB;iBAAM,IAAI,GAAG,KAAK,CAAC,EAAE;gBAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;aACzB;iBAAM,IAAI,GAAG,KAAK,EAAE,EAAE;gBACnB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;aACrB;iBAAM,IAAI,GAAG,KAAK,EAAE,EAAE;gBACnB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;aACvB;iBAAM,IAAI,GAAG,KAAK,EAAE,EAAE;gBACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;aAC1B;iBAAM,IAAI,GAAG,KAAK,EAAE,EAAE;gBACnB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;aAClB;iBAAM,IAAI,GAAG,KAAK,EAAE,EAAE;gBACnB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;aAClB;iBAAM,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;gBAClC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;aAC7C;iBAAM,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;gBAClC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;aAC7C;iBAAM,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;gBAClC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;aAC7C;iBAAM,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE;gBACtC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;aAC5C;iBAAM,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,EAAE;gBAKjC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;oBAErB,IAAI,aAAa,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC;oBAEjC,IAAI,QAAQ,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;oBAGhC,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;wBACzC,IAAI,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBACnD,IAAI,aAAa,IAAI,CAAC,IAAI,aAAa,IAAI,GAAG,EAAE;4BAC5C,IAAI,aAAa;gCACb,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;;gCAE1C,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;yBACjD;qBACJ;oBAGD,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;wBACzC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBACvC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBACvC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;wBAEvC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE;4BACtE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,UAAU,EAAE,WAAW,EAAC,CAAC;4BACjD,IAAI,aAAa;gCACb,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;;gCAEZ,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;yBACnB;qBACJ;iBACJ;aACJ;SACJ;IACH,CAAC;IAEO,iBAAiB,CAAC,QAAqB;QAC3C,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC;QAExB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAChB,OAAO,GAAG,CAAC;QAEf,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;QAGpC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,EAAE,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,IAAI;YACzG,OAAO,GAAG,CAAC;QAEf,IAAI,MAAM,GAAY,EAAE,CAAC;QACzB,IAAI,OAAO,GAAY,EAAE,CAAC;QAE1B,IAAI,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;QACrB,IAAI,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;QAGrB,IAAI,QAAQ,CAAC,IAAI;YACb,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAEpC,IAAI,QAAQ,CAAC,MAAM;YACf,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAErC,IAAI,QAAQ,CAAC,SAAS;YAClB,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YAEpB,IAAI,EAAE;gBACF,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,EAAE;gBACF,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;SACtD;aAAM;YAEH,IAAI,EAAE,EAAE;gBACJ,IAAI,EAAE,CAAC,UAAU,KAAK,WAAW,EAAE;oBAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,KAAK,CAAC,CAAC;iBACvC;qBAAM;oBACH,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBACjD;aACJ;YACD,IAAI,EAAE,EAAE;gBACJ,IAAI,EAAE,CAAC,UAAU,KAAK,WAAW,EAAE;oBAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,KAAK,CAAC,CAAC;iBACvC;qBAAM;oBACH,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBAC5D;aACJ;SACJ;QAED,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,YAAY,GAAG,EAAE,CAAC;QAEtB,IAAI,OAAO,CAAC,MAAM;YACd,YAAY,GAAG,WAAW,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAEnD,IAAI,MAAM,CAAC,MAAM;YACb,YAAY,GAAG,WAAW,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAElD,OAAO,QAAQ,YAAY,GAAG,YAAY,IAAI,GAAG,SAAS,CAAC;IAC/D,CAAC;IAAA,CAAC;IAEM,iBAAiB,CAAC,GAAc;QAGpC,IAAI,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAChB,OAAO,EAAE,CAAC;QAEd,IAAI,CAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC/B,OAAO,EAAE,CAAC;QAEd,IAAI,MAAM,GAAG,YAAY,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QACxG,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ;AAOD,SAAS,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK;IAE1B,IAAI,SAAS,GAAU,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAGtC,IAAI,KAAK,GAAG,gCAAgC,CAAC;IAC7C,IAAI,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAID,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK;IAE3B,IAAI,SAAS,GAAU,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAGtC,IAAI,KAAK,GAAG,gCAAgC,CAAC;IAC7C,IAAI,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC"}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.ts b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3c691646a1f6e71be9c13d4e2800e0e932d8f2bf
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/ansi_up.ts
@@ -0,0 +1,783 @@
+/* ansi_up.js
+ * author : Dru Nelson
+ * license : MIT
+ * http://github.com/drudru/ansi_up
+ */
+
+"use strict";
+
+//
+// INTERFACES
+//
+
+interface AU_Color
+{
+ rgb:number[];
+ class_name:string;
+}
+
+// Represents the output of process_ansi(): a snapshot of the AnsiUp state machine
+// at a given point in time, which wraps a fragment of text. This would allow deferred
+// processing of text fragments and colors, if ever needed.
+interface TextWithAttr {
+ fg:AU_Color;
+ bg:AU_Color;
+ bold:boolean;
+ faint:boolean;
+ italic: boolean;
+ underline: boolean;
+ text:string;
+}
+
+// Used internally when breaking up the raw text into packets
+
+enum PacketKind {
+ EOS,
+ Text,
+ Incomplete, // An Incomplete ESC sequence
+ ESC, // A single ESC char - random
+ Unknown, // A valid CSI but not an SGR code
+ SGR, // Select Graphic Rendition
+ OSCURL, // Operating System Command
+}
+
+interface TextPacket {
+ kind:PacketKind;
+ text:string;
+ url:string;
+}
+
+//
+// MAIN CLASS
+//
+
+export class AnsiUp
+{
+ VERSION = "6.0.2";
+
+ //
+ // *** SEE README ON GITHUB FOR PUBLIC API ***
+ //
+
+ // 256 Colors Palette
+ // CSS RGB strings - ex. "255, 255, 255"
+ private ansi_colors:AU_Color[][];
+ private palette_256:AU_Color[];
+
+ private fg:AU_Color;
+ private bg:AU_Color;
+ private bold:boolean;
+ private faint:boolean;
+ private italic: boolean;
+ private underline:boolean;
+ private _use_classes:boolean;
+
+ private _csi_regex:RegExp;
+
+ private _osc_st:RegExp;
+ private _osc_regex:RegExp;
+
+ private _url_allowlist:{};
+ private _escape_html:boolean;
+
+ private _buffer:string;
+
+ private _boldStyle:string;
+ private _faintStyle:string;
+ private _italicStyle:string;
+ private _underlineStyle:string;
+
+
+ constructor()
+ {
+ // All construction occurs here
+ this.setup_palettes();
+ this._use_classes = false;
+
+ this.bold = false;
+ this.faint = false;
+ this.italic = false;
+ this.underline = false;
+ this.fg = this.bg = null;
+
+ this._buffer = '';
+
+ this._url_allowlist = { 'http':1, 'https':1 };
+ this._escape_html = true;
+
+ this.boldStyle = 'font-weight:bold';
+ this.faintStyle = 'opacity:0.7';
+ this.italicStyle = 'font-style:italic';
+ this.underlineStyle = 'text-decoration:underline'
+ }
+
+ set use_classes(arg:boolean)
+ {
+ this._use_classes = arg;
+ }
+
+ get use_classes():boolean
+ {
+ return this._use_classes;
+ }
+
+ set url_allowlist(arg:{})
+ {
+ this._url_allowlist = arg;
+ }
+
+ get url_allowlist():{}
+ {
+ return this._url_allowlist;
+ }
+
+ set escape_html(arg:boolean)
+ {
+ this._escape_html = arg;
+ }
+
+ get escape_html():boolean
+ {
+ return this._escape_html;
+ }
+
+ set boldStyle(arg:string) { this._boldStyle = arg; }
+ get boldStyle():string { return this._boldStyle; }
+ set faintStyle(arg:string) { this._faintStyle = arg; }
+ get faintStyle():string { return this._faintStyle; }
+ set italicStyle(arg:string) { this._italicStyle = arg; }
+ get italicStyle():string { return this._italicStyle; }
+ set underlineStyle(arg:string) { this._underlineStyle = arg; }
+ get underlineStyle():string { return this._underlineStyle; }
+
+
+ private setup_palettes():void
+ {
+ this.ansi_colors =
+ [
+ // Normal colors
+ [
+ { rgb: [ 0, 0, 0], class_name: "ansi-black" },
+ { rgb: [187, 0, 0], class_name: "ansi-red" },
+ { rgb: [ 0, 187, 0], class_name: "ansi-green" },
+ { rgb: [187, 187, 0], class_name: "ansi-yellow" },
+ { rgb: [ 0, 0, 187], class_name: "ansi-blue" },
+ { rgb: [187, 0, 187], class_name: "ansi-magenta" },
+ { rgb: [ 0, 187, 187], class_name: "ansi-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-white" }
+ ],
+
+ // Bright colors
+ [
+ { rgb: [ 85, 85, 85], class_name: "ansi-bright-black" },
+ { rgb: [255, 85, 85], class_name: "ansi-bright-red" },
+ { rgb: [ 0, 255, 0], class_name: "ansi-bright-green" },
+ { rgb: [255, 255, 85], class_name: "ansi-bright-yellow" },
+ { rgb: [ 85, 85, 255], class_name: "ansi-bright-blue" },
+ { rgb: [255, 85, 255], class_name: "ansi-bright-magenta" },
+ { rgb: [ 85, 255, 255], class_name: "ansi-bright-cyan" },
+ { rgb: [255, 255, 255], class_name: "ansi-bright-white" }
+ ]
+ ];
+
+ this.palette_256 = [];
+
+ // Index 0..15 : Ansi-Colors
+ this.ansi_colors.forEach( palette => {
+ palette.forEach( rec => {
+ this.palette_256.push(rec);
+ });
+ });
+
+ // Index 16..231 : RGB 6x6x6
+ // https://gist.github.com/jasonm23/2868981#file-xterm-256color-yaml
+ let levels = [0, 95, 135, 175, 215, 255];
+ for (let r = 0; r < 6; ++r) {
+ for (let g = 0; g < 6; ++g) {
+ for (let b = 0; b < 6; ++b) {
+ let col = {rgb:[levels[r], levels[g], levels[b]], class_name:'truecolor'};
+ this.palette_256.push(col);
+ }
+ }
+ }
+
+ // Index 232..255 : Grayscale
+ let grey_level = 8;
+ for (let i = 0; i < 24; ++i, grey_level += 10) {
+ let gry = {rgb:[grey_level, grey_level, grey_level], class_name:'truecolor'};
+ this.palette_256.push(gry);
+ }
+ }
+
+ private escape_txt_for_html(txt:string):string
+ {
+ if (!this._escape_html)
+ return txt;
+ return txt.replace(/[&<>"']/gm, (str) => {
+ if (str === "&") return "&";
+ if (str === "<") return "<";
+ if (str === ">") return ">";
+ if (str === "\"") return """;
+ if (str === "'") return "'";
+ });
+ }
+
+ private append_buffer(txt:string) {
+
+ var str = this._buffer + txt;
+ this._buffer = str;
+ }
+
+ private get_next_packet():TextPacket {
+
+ var pkt =
+ {
+ kind: PacketKind.EOS,
+ text: '',
+ url: ''
+ } ;
+
+ var len = this._buffer.length;
+ if (len == 0)
+ return pkt;
+
+ var pos = this._buffer.indexOf("\x1B");
+
+ // The most common case, no ESC codes
+ if (pos == -1)
+ {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer;
+ this._buffer = '';
+ return pkt;
+ }
+
+ if (pos > 0)
+ {
+ pkt.kind = PacketKind.Text;
+ pkt.text = this._buffer.slice(0, pos);
+ this._buffer = this._buffer.slice(pos);
+ return pkt;
+ }
+
+ // NOW WE HANDLE ESCAPES
+ if (pos == 0)
+ {
+ // All of the sequences typically need at least 3 characters
+ // So, wait until we have at least that many
+ if (len < 3)
+ {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+
+ var next_char = this._buffer.charAt(1);
+
+ // We treat this as a single ESC
+ // No transformation
+ if ((next_char != '[') && (next_char != ']') && (next_char != '('))
+ {
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+
+ // OK is this an SGR or OSC that we handle
+
+ // SGR CHECK
+ if (next_char == '[')
+ {
+ // We do this regex initialization here so
+ // we can keep the regex close to its use (Readability)
+
+ // All ansi codes are typically in the following format.
+ // We parse it and focus specifically on the
+ // graphics commands (SGR)
+ //
+ // CONTROL-SEQUENCE-INTRODUCER CSI (ESC, '[')
+ // PRIVATE-MODE-CHAR (!, <, >, ?)
+ // Numeric parameters separated by semicolons ('0' - '9', ';')
+ // Intermediate-modifiers (0x20 - 0x2f)
+ // COMMAND-CHAR (0x40 - 0x7e)
+ //
+
+ if (!this._csi_regex) {
+
+ this._csi_regex = rgx`
+ ^ # beginning of line
+ #
+ # First attempt
+ (?: # legal sequence
+ \x1b\[ # CSI
+ ([\x3c-\x3f]?) # private-mode char
+ ([\d;]*) # any digits or semicolons
+ ([\x20-\x2f]? # an intermediate modifier
+ [\x40-\x7e]) # the command
+ )
+ | # alternate (second attempt)
+ (?: # illegal sequence
+ \x1b\[ # CSI
+ [\x20-\x7e]* # anything legal
+ ([\x00-\x1f:]) # anything illegal
+ )
+ `;
+ }
+
+ let match = this._buffer.match(this._csi_regex);
+
+ // This match is guaranteed to terminate (even on
+ // invalid input). The key is to match on legal and
+ // illegal sequences.
+ // The first alternate matches everything legal and
+ // the second matches everything illegal.
+ //
+ // If it doesn't match, then we have not received
+ // either the full sequence or an illegal sequence.
+ // If it does match, the presence of field 4 tells
+ // us whether it was legal or illegal.
+
+ if (match === null)
+ {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+
+ // match is an array
+ // 0 - total match
+ // 1 - private mode chars group
+ // 2 - digits and semicolons group
+ // 3 - command
+ // 4 - illegal char
+
+ if (match[4])
+ {
+ // Illegal sequence, just remove the ESC
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+
+ // If not a valid SGR, we don't handle
+ if ( (match[1] != '') || (match[3] != 'm'))
+ pkt.kind = PacketKind.Unknown;
+ else
+ pkt.kind = PacketKind.SGR;
+
+ pkt.text = match[2] // Just the parameters
+
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ else
+ // OSC CHECK
+ if (next_char == ']')
+ {
+ if (len < 4)
+ {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+
+ if ( (this._buffer.charAt(2) != '8')
+ || (this._buffer.charAt(3) != ';') )
+ {
+ // This is not a match, so we'll just treat it as ESC
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+
+ // We do this regex initialization here so
+ // we can keep the regex close to its use (Readability)
+
+ // Matching a Hyperlink OSC with a regex is difficult
+ // because Javascript's regex engine doesn't support
+ // 'partial match' support.
+ //
+ // Therefore, we require the system to match the
+ // string-terminator(ST) before attempting a match.
+ // Once we find it, we attempt the Hyperlink-Begin
+ // match.
+ // If that goes ok, we scan forward for the next
+ // ST.
+ // Finally, we try to match it all and return
+ // the sequence.
+ // Also, it is important to note that we consider
+ // certain control characters as an invalidation of
+ // the entire sequence.
+
+ // We do regex initializations here so
+ // we can keep the regex close to its use (Readability)
+
+
+ // STRING-TERMINATOR
+ // This is likely to terminate in most scenarios
+ // because it will terminate on a newline
+
+ if (!this._osc_st) {
+
+ this._osc_st = rgxG`
+ (?: # legal sequence
+ (\x1b\\) # ESC \
+ | # alternate
+ (\x07) # BEL (what xterm did)
+ )
+ | # alternate (second attempt)
+ ( # illegal sequence
+ [\x00-\x06] # anything illegal
+ | # alternate
+ [\x08-\x1a] # anything illegal
+ | # alternate
+ [\x1c-\x1f] # anything illegal
+ )
+ `;
+ }
+
+ // VERY IMPORTANT
+ // We do a stateful regex match with exec.
+ // If the regex is global, and it used with 'exec',
+ // then it will search starting at the 'lastIndex'
+ // If it matches, the regex can be used again to
+ // find the next match.
+ this._osc_st.lastIndex = 0;
+
+
+ {
+ let match = this._osc_st.exec( this._buffer );
+
+ if (match === null)
+ {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+
+ // If an illegal character was found, bail on the match
+ if (match[3])
+ {
+ // Illegal sequence, just remove the ESC
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+
+
+
+ // OK - we might have the prefix and URI
+ // Lets start our search for the next ST
+ // past this index
+
+ {
+ let match = this._osc_st.exec( this._buffer );
+
+ if (match === null)
+ {
+ pkt.kind = PacketKind.Incomplete;
+ return pkt;
+ }
+
+ // If an illegal character was found, bail on the match
+ if (match[3])
+ {
+ // Illegal sequence, just remove the ESC
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+ }
+
+ // OK, at this point we should have a FULL match!
+ //
+ // Lets try to match that now
+
+ if (!this._osc_regex) {
+
+ this._osc_regex = rgx`
+ ^ # beginning of line
+ #
+ \x1b\]8; # OSC Hyperlink
+ [\x20-\x3a\x3c-\x7e]* # params (excluding ;)
+ ; # end of params
+ ([\x21-\x7e]{0,512}) # URL capture
+ (?: # ST
+ (?:\x1b\\) # ESC \
+ | # alternate
+ (?:\x07) # BEL (what xterm did)
+ )
+ ([\x20-\x7e]+) # TEXT capture
+ \x1b\]8;; # OSC Hyperlink End
+ (?: # ST
+ (?:\x1b\\) # ESC \
+ | # alternate
+ (?:\x07) # BEL (what xterm did)
+ )
+ `;
+ }
+
+ let match = this._buffer.match(this._osc_regex);
+
+ if (match === null)
+ {
+ // Illegal sequence, just remove the ESC
+ pkt.kind = PacketKind.ESC;
+ pkt.text = this._buffer.slice(0, 1);
+ this._buffer = this._buffer.slice(1);
+ return pkt;
+ }
+
+ // match is an array
+ // 0 - total match
+ // 1 - URL
+ // 2 - Text
+
+ // If a valid SGR
+ pkt.kind = PacketKind.OSCURL;
+ pkt.url = match[1];
+ pkt.text = match[2];
+
+ var rpos = match[0].length;
+ this._buffer = this._buffer.slice(rpos);
+ return pkt;
+ }
+ else
+ // Other ESC CHECK
+ if (next_char == '(')
+ {
+ // This specifies the character set, which
+ // should just be ignored
+
+ // We have at least 3, so drop the sequence
+ pkt.kind = PacketKind.Unknown;
+ this._buffer = this._buffer.slice(3);
+ return pkt;
+ }
+ }
+ }
+
+ ansi_to_html(txt:string):string {
+
+ this.append_buffer(txt);
+
+ var blocks:string[] = [];
+
+ while (true)
+ {
+ var packet = this.get_next_packet();
+
+ if ( (packet.kind == PacketKind.EOS)
+ || (packet.kind == PacketKind.Incomplete) )
+ break;
+
+ //Drop single ESC or Unknown CSI
+ if ( (packet.kind == PacketKind.ESC)
+ || (packet.kind == PacketKind.Unknown) )
+ continue;
+
+ if (packet.kind == PacketKind.Text)
+ blocks.push( this.transform_to_html(this.with_state(packet)) );
+ else
+ if (packet.kind == PacketKind.SGR)
+ this.process_ansi(packet);
+ else
+ if (packet.kind == PacketKind.OSCURL)
+ blocks.push( this.process_hyperlink(packet) );
+ }
+
+ return blocks.join("");
+ }
+
+ private with_state(pkt:TextPacket):TextWithAttr {
+ return { bold: this.bold, faint: this.faint, italic: this.italic, underline: this.underline, fg: this.fg, bg: this.bg, text: pkt.text };
+ }
+
+ private process_ansi(pkt:TextPacket)
+ {
+ // Ok - we have a valid "SGR" (Select Graphic Rendition)
+
+ let sgr_cmds = pkt.text.split(';');
+
+ // Each of these params affects the SGR state
+
+ // Why do we shift through the array instead of a forEach??
+ // ... because some commands consume the params that follow !
+
+ while (sgr_cmds.length > 0) {
+ let sgr_cmd_str = sgr_cmds.shift();
+ let num = parseInt(sgr_cmd_str, 10);
+
+ // TODO
+ // AT SOME POINT, JUST CONVERT TO A LOOKUP TABLE
+ if (isNaN(num) || num === 0) {
+ this.fg = null;
+ this.bg = null;
+ this.bold = false;
+ this.faint = false;
+ this.italic = false;
+ this.underline = false;
+
+ } else if (num === 1) { this.bold = true;
+ } else if (num === 2) { this.faint = true;
+ } else if (num === 3) { this.italic = true;
+ } else if (num === 4) { this.underline = true;
+ } else if (num === 21) { this.bold = false;
+ } else if (num === 22) { this.faint = false; this.bold = false;
+ } else if (num === 23) { this.italic = false;
+ } else if (num === 24) { this.underline = false;
+
+ } else if (num === 39) { this.fg = null;
+ } else if (num === 49) { this.bg = null;
+
+ } else if ((num >= 30) && (num < 38)) { this.fg = this.ansi_colors[0][(num - 30)];
+ } else if ((num >= 40) && (num < 48)) { this.bg = this.ansi_colors[0][(num - 40)];
+ } else if ((num >= 90) && (num < 98)) { this.fg = this.ansi_colors[1][(num - 90)];
+ } else if ((num >= 100) && (num < 108)) { this.bg = this.ansi_colors[1][(num - 100)];
+
+ } else if (num === 38 || num === 48) {
+
+ // extended set foreground/background color
+
+ // validate that param exists
+ if (sgr_cmds.length > 0) {
+ // extend color (38=fg, 48=bg)
+ let is_foreground = (num === 38);
+
+ let mode_cmd = sgr_cmds.shift();
+
+ // MODE '5' - 256 color palette
+ if (mode_cmd === '5' && sgr_cmds.length > 0) {
+ let palette_index = parseInt(sgr_cmds.shift(), 10);
+ if (palette_index >= 0 && palette_index <= 255) {
+ if (is_foreground)
+ this.fg = this.palette_256[palette_index];
+ else
+ this.bg = this.palette_256[palette_index];
+ }
+ }
+
+ // MODE '2' - True Color
+ if (mode_cmd === '2' && sgr_cmds.length > 2) {
+ let r = parseInt(sgr_cmds.shift(), 10);
+ let g = parseInt(sgr_cmds.shift(), 10);
+ let b = parseInt(sgr_cmds.shift(), 10);
+
+ if ((r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255)) {
+ let c = { rgb: [r,g,b], class_name: 'truecolor'};
+ if (is_foreground)
+ this.fg = c;
+ else
+ this.bg = c;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private transform_to_html(fragment:TextWithAttr):string {
+ let txt = fragment.text;
+
+ if (txt.length === 0)
+ return txt;
+
+ txt = this.escape_txt_for_html(txt);
+
+ // If colors not set, default style is used
+ if (!fragment.bold && !fragment.italic && !fragment.underline && fragment.fg === null && fragment.bg === null)
+ return txt;
+
+ let styles:string[] = [];
+ let classes:string[] = [];
+
+ let fg = fragment.fg;
+ let bg = fragment.bg;
+
+ // Note on bold: https://stackoverflow.com/questions/6737005/what-are-some-advantages-to-using-span-style-font-weightbold-rather-than-b?rq=1
+ if (fragment.bold) styles.push(this._boldStyle);
+ if (fragment.faint) styles.push(this._faintStyle);
+ if (fragment.italic) styles.push(this._italicStyle);
+ if (fragment.underline) styles.push(this._underlineStyle);
+
+ if (!this._use_classes) {
+ // USE INLINE STYLES
+ if (fg)
+ styles.push(`color:rgb(${fg.rgb.join(',')})`);
+ if (bg)
+ styles.push(`background-color:rgb(${bg.rgb})`);
+ } else {
+ // USE CLASSES
+ if (fg) {
+ if (fg.class_name !== 'truecolor') {
+ classes.push(`${fg.class_name}-fg`);
+ } else {
+ styles.push(`color:rgb(${fg.rgb.join(',')})`);
+ }
+ }
+ if (bg) {
+ if (bg.class_name !== 'truecolor') {
+ classes.push(`${bg.class_name}-bg`);
+ } else {
+ styles.push(`background-color:rgb(${bg.rgb.join(',')})`);
+ }
+ }
+ }
+
+ let class_string = '';
+ let style_string = '';
+
+ if (classes.length)
+ class_string = ` class="${classes.join(' ')}"`;
+
+ if (styles.length)
+ style_string = ` style="${styles.join(';')}"`;
+
+ return `${txt}`;
+ };
+
+ private process_hyperlink(pkt:TextPacket):string
+ {
+ // Check URL scheme
+ let parts = pkt.url.split(':');
+ if (parts.length < 1)
+ return '';
+
+ if (! this._url_allowlist[parts[0]])
+ return '';
+
+ let result = `${this.escape_txt_for_html(pkt.text)}`;
+ return result;
+ }
+}
+
+//
+// PRIVATE FUNCTIONS
+//
+
+// ES5 template string transformer
+function rgx(tmplObj, ...subst) {
+ // Use the 'raw' value so we don't have to double backslash in a template string
+ let regexText:string = tmplObj.raw[0];
+
+ // Remove white-space and comments
+ let wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ let txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2);
+}
+
+// ES5 template string transformer
+// Multi-Line On
+function rgxG(tmplObj, ...subst) {
+ // Use the 'raw' value so we don't have to double backslash in a template string
+ let regexText:string = tmplObj.raw[0];
+
+ // Remove white-space and comments
+ let wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
+ let txt2 = regexText.replace(wsrgx, '');
+ return new RegExp(txt2, 'g');
+}
+
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser.html b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser.html
new file mode 100644
index 0000000000000000000000000000000000000000..c59d3941ff490cde0e23490d5d4b79ccb0e577c4
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser_amd.html b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser_amd.html
new file mode 100644
index 0000000000000000000000000000000000000000..ddd981d9bb754a1ccc773ac56b06939285af543b
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/browser_amd.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/jquery-1.7.2.min.js b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/jquery-1.7.2.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..16ad06c5acaad09ee4d6e9d7c428506db028aeeb
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/ansi_up/examples/jquery-1.7.2.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.2 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;ca",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q=""+"",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
+a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,""],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div","
"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
+.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>$2>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/
+
+
+```
+
+```javascript
+// index.js -> bundle.js
+var QRCode = require('qrcode')
+var canvas = document.getElementById('canvas')
+
+QRCode.toCanvas(canvas, 'sample text', function (error) {
+ if (error) console.error(error)
+ console.log('success!');
+})
+```
+
+#### Precompiled bundle
+```html
+
+
+
+
+```
+
+If you install through `npm`, precompiled files will be available in `node_modules/qrcode/build/` folder.
+
+The precompiled bundle have support for [Internet Explorer 10+, Safari 5.1+, and all evergreen browsers](https://browserl.ist/?q=defaults%2C+IE+%3E%3D+10%2C+Safari+%3E%3D+5.1).
+
+### NodeJS
+Require the module `qrcode`
+
+```javascript
+var QRCode = require('qrcode')
+
+QRCode.toDataURL('I am a pony!', function (err, url) {
+ console.log(url)
+})
+```
+
+render a qrcode for the terminal
+```js
+var QRCode = require('qrcode')
+
+QRCode.toString('I am a pony!',{type:'terminal'}, function (err, url) {
+ console.log(url)
+})
+```
+
+### ES6/ES7
+Promises and Async/Await can be used in place of callback function.
+
+```javascript
+import QRCode from 'qrcode'
+
+// With promises
+QRCode.toDataURL('I am a pony!')
+ .then(url => {
+ console.log(url)
+ })
+ .catch(err => {
+ console.error(err)
+ })
+
+// With async/await
+const generateQR = async text => {
+ try {
+ console.log(await QRCode.toDataURL(text))
+ } catch (err) {
+ console.error(err)
+ }
+}
+```
+
+## Error correction level
+Error correction capability allows to successfully scan a QR Code even if the symbol is dirty or damaged.
+Four levels are available to choose according to the operating environment.
+
+Higher levels offer a better error resistance but reduce the symbol's capacity.
+If the chances that the QR Code symbol may be corrupted are low (for example if it is showed through a monitor)
+is possible to safely use a low error level such as `Low` or `Medium`.
+
+Possible levels are shown below:
+
+| Level | Error resistance |
+|------------------|:----------------:|
+| **L** (Low) | **~7%** |
+| **M** (Medium) | **~15%** |
+| **Q** (Quartile) | **~25%** |
+| **H** (High) | **~30%** |
+
+The percentage indicates the maximum amount of damaged surface after which the symbol becomes unreadable.
+
+Error level can be set through `options.errorCorrectionLevel` property.
+If not specified, the default value is `M`.
+
+```javascript
+QRCode.toDataURL('some text', { errorCorrectionLevel: 'H' }, function (err, url) {
+ console.log(url)
+})
+```
+
+## QR Code capacity
+Capacity depends on symbol version and error correction level. Also encoding modes may influence the amount of storable data.
+
+The QR Code versions range from version **1** to version **40**.
+Each version has a different number of modules (black and white dots), which define the symbol's size.
+For version 1 they are `21x21`, for version 2 `25x25` e so on.
+Higher is the version, more are the storable data, and of course bigger will be the QR Code symbol.
+
+The table below shows the maximum number of storable characters in each encoding mode and for each error correction level.
+
+| Mode | L | M | Q | H |
+|--------------|------|------|------|------|
+| Numeric | 7089 | 5596 | 3993 | 3057 |
+| Alphanumeric | 4296 | 3391 | 2420 | 1852 |
+| Byte | 2953 | 2331 | 1663 | 1273 |
+| Kanji | 1817 | 1435 | 1024 | 784 |
+
+**Note:** Maximum characters number can be different when using [Mixed modes](#mixed-modes).
+
+QR Code version can be set through `options.version` property.
+If no version is specified, the more suitable value will be used. Unless a specific version is required, this option is not needed.
+
+```javascript
+QRCode.toDataURL('some text', { version: 2 }, function (err, url) {
+ console.log(url)
+})
+```
+
+## Encoding modes
+Modes can be used to encode a string in a more efficient way.
+A mode may be more suitable than others depending on the string content.
+A list of supported modes are shown in the table below:
+
+| Mode | Characters | Compression |
+|--------------|-----------------------------------------------------------|-------------------------------------------|
+| Numeric | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 | 3 characters are represented by 10 bits |
+| Alphanumeric | 0–9, A–Z (upper-case only), space, $, %, *, +, -, ., /, : | 2 characters are represented by 11 bits |
+| Kanji | Characters from the Shift JIS system based on JIS X 0208 | 2 kanji are represented by 13 bits |
+| Byte | Characters from the ISO/IEC 8859-1 character set | Each characters are represented by 8 bits |
+
+Choose the right mode may be tricky if the input text is unknown.
+In these cases **Byte** mode is the best choice since all characters can be encoded with it. (See [Multibyte characters](#multibyte-characters))
+However, if the QR Code reader supports mixed modes, using [Auto mode](#auto-mode) may produce better results.
+
+### Mixed modes
+Mixed modes are also possible. A QR code can be generated from a series of segments having different encoding modes to optimize the data compression.
+However, switching from a mode to another has a cost which may lead to a worst result if it's not taken into account.
+See [Manual mode](#manual-mode) for an example of how to specify segments with different encoding modes.
+
+### Auto mode
+By **default**, automatic mode selection is used.
+The input string is automatically splitted in various segments optimized to produce the shortest possible bitstream using mixed modes.
+This is the preferred way to generate the QR Code.
+
+For example, the string **ABCDE12345678?A1A** will be splitted in 3 segments with the following modes:
+
+| Segment | Mode |
+|----------|--------------|
+| ABCDE | Alphanumeric |
+| 12345678 | Numeric |
+| ?A1A | Byte |
+
+Any other combinations of segments and modes will result in a longer bitstream.
+If you need to keep the QR Code size small, this mode will produce the best results.
+
+### Manual mode
+If auto mode doesn't work for you or you have specific needs, is also possible to manually specify each segment with the relative mode.
+In this way no segment optimizations will be applied under the hood.
+Segments list can be passed as an array of object:
+
+```javascript
+ var QRCode = require('qrcode')
+
+ var segs = [
+ { data: 'ABCDEFG', mode: 'alphanumeric' },
+ { data: '0123456', mode: 'numeric' }
+ ]
+
+ QRCode.toDataURL(segs, function (err, url) {
+ console.log(url)
+ })
+```
+
+### Kanji mode
+With kanji mode is possible to encode characters from the Shift JIS system in an optimized way.
+Unfortunately, there isn't a way to calculate a Shifted JIS values from, for example, a character encoded in UTF-8, for this reason a conversion table from the input characters to the SJIS values is needed.
+This table is not included by default in the bundle to keep the size as small as possible.
+
+If your application requires kanji support, you will need to pass a function that will take care of converting the input characters to appropriate values.
+
+An helper method is provided by the lib through an optional file that you can include as shown in the example below.
+
+**Note:** Support for Kanji mode is only needed if you want to benefit of the data compression, otherwise is still possible to encode kanji using Byte mode (See [Multibyte characters](#multibyte-characters)).
+
+```javascript
+ var QRCode = require('qrcode')
+ var toSJIS = require('qrcode/helper/to-sjis')
+
+ QRCode.toDataURL(kanjiString, { toSJISFunc: toSJIS }, function (err, url) {
+ console.log(url)
+ })
+```
+
+With precompiled bundle:
+
+```html
+
+
+
+
+
+```
+
+## Binary data
+QR Codes can hold arbitrary byte-based binary data. If you attempt to create a binary QR Code by first converting the data to a JavaScript string, it will fail to encode propery because string encoding adds additional bytes. Instead, you must pass a [`Uint8ClampedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) or compatible array, or a Node [Buffer](https://nodejs.org/api/buffer.html), as follows:
+
+```javascript
+// Regular array example
+// WARNING: Element values will be clamped to 0-255 even if your data contains higher values.
+const QRCode = require('qrcode')
+QRCode.toFile(
+ 'foo.png',
+ [{ data: [253,254,255], mode: 'byte' }],
+ ...options...,
+ ...callback...
+)
+```
+
+```javascript
+// Uint8ClampedArray example
+const QRCode = require('qrcode')
+
+QRCode.toFile(
+ 'foo.png',
+ [{ data: new Uint8ClampedArray([253,254,255]), mode: 'byte' }],
+ ...options...,
+ ...callback...
+)
+```
+
+```javascript
+// Node Buffer example
+// WARNING: Element values will be clamped to 0-255 even if your data contains higher values.
+const QRCode = require('qrcode')
+
+QRCode.toFile(
+ 'foo.png',
+ [{ data: Buffer.from([253,254,255]), mode: 'byte' }],
+ ...options...,
+ ...callback...
+)
+```
+
+TypeScript users: if you are using [@types/qrcode](https://www.npmjs.com/package/@types/qrcode), you will need to add a `// @ts-ignore` above the data segment because it expects `data: string`.
+
+## Multibyte characters
+Support for multibyte characters isn't present in the initial QR Code standard, but is possible to encode UTF-8 characters in Byte mode.
+
+QR Codes provide a way to specify a different type of character set through ECI (Extended Channel Interpretation), but it's not fully implemented in this lib yet.
+
+Most QR Code readers, however, are able to recognize multibyte characters even without ECI.
+
+Note that a single Kanji/Kana or Emoji can take up to 4 bytes.
+
+## API
+Browser:
+- [create()](#createtext-options)
+- [toCanvas()](#tocanvascanvaselement-text-options-cberror)
+- [toDataURL()](#todataurltext-options-cberror-url)
+- [toString()](#tostringtext-options-cberror-string)
+
+Server:
+- [create()](#createtext-options)
+- [toCanvas()](#tocanvascanvas-text-options-cberror)
+- [toDataURL()](#todataurltext-options-cberror-url-1)
+- [toString()](#tostringtext-options-cberror-string-1)
+- [toFile()](#tofilepath-text-options-cberror)
+- [toFileStream()](#tofilestreamstream-text-options)
+
+### Browser API
+#### `create(text, [options])`
+Creates QR Code symbol and returns a qrcode object.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+See [QR Code options](#qr-code-options).
+
+##### `returns`
+Type: `Object`
+
+```javascript
+// QRCode object
+{
+ modules, // Bitmatrix class with modules data
+ version, // Calculated QR Code version
+ errorCorrectionLevel, // Error Correction Level
+ maskPattern, // Calculated Mask pattern
+ segments // Generated segments
+}
+```
+
+
+
+#### `toCanvas(canvasElement, text, [options], [cb(error)])`
+#### `toCanvas(text, [options], [cb(error, canvas)])`
+Draws qr code symbol to canvas.
+If `canvasElement` is omitted a new canvas is returned.
+
+##### `canvasElement`
+Type: `DOMElement`
+
+Canvas where to draw QR Code.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+See [Options](#options).
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+##### Example
+```javascript
+QRCode.toCanvas('text', { errorCorrectionLevel: 'H' }, function (err, canvas) {
+ if (err) throw err
+
+ var container = document.getElementById('container')
+ container.appendChild(canvas)
+})
+```
+
+
+
+#### `toDataURL(text, [options], [cb(error, url)])`
+#### `toDataURL(canvasElement, text, [options], [cb(error, url)])`
+Returns a Data URI containing a representation of the QR Code image.
+If provided, `canvasElement` will be used as canvas to generate the data URI.
+
+##### `canvasElement`
+Type: `DOMElement`
+
+Canvas where to draw QR Code.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+- ###### `type`
+ Type: `String`
+ Default: `image/png`
+
+ Data URI format.
+ Possible values are: `image/png`, `image/jpeg`, `image/webp`.
+
+- ###### `rendererOpts.quality`
+ Type: `Number`
+ Default: `0.92`
+
+ A Number between `0` and `1` indicating image quality if the requested type is `image/jpeg` or `image/webp`.
+
+See [Options](#options) for other settings.
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+##### Example
+```javascript
+var opts = {
+ errorCorrectionLevel: 'H',
+ type: 'image/jpeg',
+ quality: 0.3,
+ margin: 1,
+ color: {
+ dark:"#010599FF",
+ light:"#FFBF60FF"
+ }
+}
+
+QRCode.toDataURL('text', opts, function (err, url) {
+ if (err) throw err
+
+ var img = document.getElementById('image')
+ img.src = url
+})
+```
+
+
+#### `toString(text, [options], [cb(error, string)])`
+
+Returns a string representation of the QR Code.
+
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+- ###### `type`
+ Type: `String`
+ Default: `utf8`
+
+ Output format.
+ Possible values are: `terminal`,`utf8`, and `svg`.
+
+See [Options](#options) for other settings.
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+##### Example
+```javascript
+QRCode.toString('http://www.google.com', function (err, string) {
+ if (err) throw err
+ console.log(string)
+})
+```
+
+
+
+
+### Server API
+#### `create(text, [options])`
+See [create](#createtext-options).
+
+
+
+#### `toCanvas(canvas, text, [options], [cb(error)])`
+Draws qr code symbol to [node canvas](https://github.com/Automattic/node-canvas).
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+See [Options](#options).
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+
+
+#### `toDataURL(text, [options], [cb(error, url)])`
+Returns a Data URI containing a representation of the QR Code image.
+Only works with `image/png` type for now.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+See [Options](#options) for other settings.
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+
+
+#### `toString(text, [options], [cb(error, string)])`
+Returns a string representation of the QR Code.
+If choosen output format is `svg` it will returns a string containing xml code.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+- ###### `type`
+ Type: `String`
+ Default: `utf8`
+
+ Output format.
+ Possible values are: `utf8`, `svg`, `terminal`.
+
+See [Options](#options) for other settings.
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+##### Example
+```javascript
+QRCode.toString('http://www.google.com', function (err, string) {
+ if (err) throw err
+ console.log(string)
+})
+```
+
+
+
+#### `toFile(path, text, [options], [cb(error)])`
+Saves QR Code to image file.
+If `options.type` is not specified, the format will be guessed from file extension.
+Recognized extensions are `png`, `svg`, `txt`.
+
+##### `path`
+Type: `String`
+
+Path where to save the file.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+- ###### `type`
+ Type: `String`
+ Default: `png`
+
+ Output format.
+ Possible values are: `png`, `svg`, `utf8`.
+
+- ###### `rendererOpts.deflateLevel` **(png only)**
+ Type: `Number`
+ Default: `9`
+
+ Compression level for deflate.
+
+- ###### `rendererOpts.deflateStrategy` **(png only)**
+ Type: `Number`
+ Default: `3`
+
+ Compression strategy for deflate.
+
+See [Options](#options) for other settings.
+
+##### `cb`
+Type: `Function`
+
+Callback function called on finish.
+
+##### Example
+```javascript
+QRCode.toFile('path/to/filename.png', 'Some text', {
+ color: {
+ dark: '#00F', // Blue dots
+ light: '#0000' // Transparent background
+ }
+}, function (err) {
+ if (err) throw err
+ console.log('done')
+})
+```
+
+
+
+#### `toFileStream(stream, text, [options])`
+Writes QR Code image to stream. Only works with `png` format for now.
+
+##### `stream`
+Type: `stream.Writable`
+
+Node stream.
+
+##### `text`
+Type: `String|Array`
+
+Text to encode or a list of objects describing segments.
+
+##### `options`
+See [Options](#options).
+
+
+
+### Options
+
+#### QR Code options
+##### `version`
+ Type: `Number`
+
+ QR Code version. If not specified the more suitable value will be calculated.
+
+##### `errorCorrectionLevel`
+ Type: `String`
+ Default: `M`
+
+ Error correction level.
+ Possible values are `low, medium, quartile, high` or `L, M, Q, H`.
+
+##### `maskPattern`
+ Type: `Number`
+
+ Mask pattern used to mask the symbol.
+ Possible values are `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`.
+ If not specified the more suitable value will be calculated.
+
+##### `toSJISFunc`
+ Type: `Function`
+
+ Helper function used internally to convert a kanji to its Shift JIS value.
+ Provide this function if you need support for Kanji mode.
+
+#### Renderers options
+##### `margin`
+ Type: `Number`
+ Default: `4`
+
+ Define how much wide the quiet zone should be.
+
+##### `scale`
+ Type: `Number`
+ Default: `4`
+
+ Scale factor. A value of `1` means 1px per modules (black dots).
+
+##### `small`
+ Type: `Boolean`
+ Default: `false`
+
+ Relevant only for terminal renderer. Outputs smaller QR code.
+
+##### `width`
+ Type: `Number`
+
+ Forces a specific width for the output image.
+ If width is too small to contain the qr symbol, this option will be ignored.
+ Takes precedence over `scale`.
+
+##### `color.dark`
+Type: `String`
+Default: `#000000ff`
+
+Color of dark module. Value must be in hex format (RGBA).
+Note: dark color should always be darker than `color.light`.
+
+##### `color.light`
+Type: `String`
+Default: `#ffffffff`
+
+Color of light module. Value must be in hex format (RGBA).
+
+
+
+## GS1 QR Codes
+There was a real good discussion here about them. but in short any qrcode generator will make gs1 compatible qrcodes, but what defines a gs1 qrcode is a header with metadata that describes your gs1 information.
+
+https://github.com/soldair/node-qrcode/issues/45
+
+
+## Credits
+This lib is based on "QRCode for JavaScript" which Kazuhiko Arase thankfully MIT licensed.
+
+## License
+[MIT](https://github.com/soldair/node-qrcode/blob/master/license)
+
+The word "QR Code" is registered trademark of:
+DENSO WAVE INCORPORATED
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/bin/qrcode b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/bin/qrcode
new file mode 100644
index 0000000000000000000000000000000000000000..dd990b63cdbfcb266263496363f47ac8f86601d7
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/bin/qrcode
@@ -0,0 +1,159 @@
+#!/usr/bin/env node
+var yargs = require('yargs')
+var qr = require('../lib')
+
+function save (file, text, options) {
+ qr.toFile(file, text, options, function (err, data) {
+ if (err) {
+ console.error('Error:', err.message)
+ process.exit(1)
+ }
+
+ console.log('saved qrcode to: ' + file + '\n')
+ })
+}
+
+function print (text, options) {
+ options.type = 'terminal'
+ qr.toString(text, options, function (err, text) {
+ if (err) {
+ console.error('Error:', err.message)
+ process.exit(1)
+ }
+
+ console.log(text)
+ })
+}
+
+function parseOptions (args) {
+ return {
+ version: args.qversion,
+ errorCorrectionLevel: args.error,
+ type: args.type,
+ small: !!args.small,
+ inverse: !!args.inverse,
+ maskPattern: args.mask,
+ margin: args.qzone,
+ width: args.width,
+ scale: args.scale,
+ color: {
+ light: args.lightcolor,
+ dark: args.darkcolor
+ }
+ }
+}
+
+function processInputs (text, opts) {
+ if (!text.length) {
+ yargs.showHelp()
+ process.exit(1)
+ }
+
+ if (opts.output) {
+ save(opts.output, text, parseOptions(opts))
+ } else {
+ print(text, parseOptions(opts))
+ }
+}
+
+var argv = yargs
+ .detectLocale(false)
+ .usage('Usage: $0 [options] ')
+ .option('v', {
+ alias: 'qversion',
+ description: 'QR Code symbol version (1 - 40)',
+ group: 'QR Code options:',
+ type: 'number'
+ })
+ .option('e', {
+ alias: 'error',
+ description: 'Error correction level',
+ choices: ['L', 'M', 'Q', 'H'],
+ group: 'QR Code options:'
+ })
+ .option('m', {
+ alias: 'mask',
+ description: 'Mask pattern (0 - 7)',
+ group: 'QR Code options:',
+ type: 'number'
+ })
+ .option('t', {
+ alias: 'type',
+ description: 'Output type',
+ choices: ['png', 'svg', 'utf8'],
+ implies: 'output',
+ group: 'Renderer options:'
+ })
+ .option('i', {
+ alias: 'inverse',
+ type: 'boolean',
+ description: 'Invert colors',
+ group: 'Renderer options:'
+ })
+ .option('w', {
+ alias: 'width',
+ description: 'Image width (px)',
+ conflicts: 'scale',
+ group: 'Renderer options:',
+ type: 'number'
+ })
+ .option('s', {
+ alias: 'scale',
+ description: 'Scale factor',
+ conflicts: 'width',
+ group: 'Renderer options:',
+ type: 'number'
+ })
+ .option('q', {
+ alias: 'qzone',
+ description: 'Quiet zone size',
+ group: 'Renderer options:',
+ type: 'number'
+ })
+ .option('l', {
+ alias: 'lightcolor',
+ description: 'Light RGBA hex color',
+ group: 'Renderer options:'
+ })
+ .option('d', {
+ alias: 'darkcolor',
+ description: 'Dark RGBA hex color',
+ group: 'Renderer options:'
+ })
+ .option('small', {
+ type: 'boolean',
+ description: 'Output smaller QR code to terminal',
+ conflicts: 'type',
+ group: 'Renderer options:'
+ })
+ .option('o', {
+ alias: 'output',
+ description: 'Output file'
+ })
+ .help('h')
+ .alias('h', 'help')
+ .version()
+ .example('$0 "some text"', 'Draw in terminal window')
+ .example('$0 -o out.png "some text"', 'Save as png image')
+ .example('$0 -d F00 -o out.png "some text"', 'Use red as foreground color')
+ .parserConfiguration({'parse-numbers': false})
+ .argv
+
+if (process.stdin.isTTY) {
+ processInputs(argv._.join(' '), argv)
+} else {
+ var text = ''
+ process.stdin.setEncoding('utf8')
+ process.stdin.on('readable', function () {
+ var chunk = process.stdin.read()
+ if (chunk !== null) {
+ text += chunk
+ }
+ })
+
+ process.stdin.on('end', function () {
+ // this process can be run as a command outside of a tty so if there was no
+ // data on stdin read from argv
+ processInputs(text.length?text:argv._.join(' '), argv)
+ })
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis-browser.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis-browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c9b3aa73c25e9e06c9f1e654bbb5103c31b2b66
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis-browser.js
@@ -0,0 +1,2 @@
+/* global QRCode */
+QRCode.toSJIS = require('./to-sjis')
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e31ba1aae2e5554845c1c37bc1f07954aab5334
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/helper/to-sjis.js
@@ -0,0 +1,100 @@
+const SJIS_UTF8 = [
+ [0x8140, ' 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+-±×'],
+ [0x8180, '÷=≠<>'],
+ [0x818f, '¥$¢£%#&*@§☆★'],
+ [0x81a6, '※〒→←↑↓〓'],
+ [0x81ca, '¬'],
+ [0x824f, '0123456789'],
+ [0x8260, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'],
+ [0x8281, 'abcdefghijklmnopqrstuvwxyz'],
+ [0x829f, 'ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん'],
+ [0x8340, 'ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ'],
+ [0x8380, 'ムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ'],
+ [0x839f, 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'],
+ [0x83bf, 'αβγδεζηθικλμνξοπρστυφχψω'],
+ [0x8440, 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'],
+ [0x8470, 'абвгдеёжзийклмн'],
+ [0x8480, 'опрстуфхцчшщъыьэюя'],
+ [0x8780, '〝〟'],
+ [0x8940, '院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円'],
+ [0x8980, '園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改'],
+ [0x8a40, '魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫'],
+ [0x8a80, '橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄'],
+ [0x8b40, '機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救'],
+ [0x8b80, '朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈'],
+ [0x8c40, '掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨'],
+ [0x8c80, '劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向'],
+ [0x8d40, '后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降'],
+ [0x8d80, '項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷'],
+ [0x8e40, '察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止'],
+ [0x8e80, '死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周'],
+ [0x8f40, '宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳'],
+ [0x8f80, '準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾'],
+ [0x9040, '拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨'],
+ [0x9080, '逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線'],
+ [0x9140, '繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻'],
+ [0x9180, '操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只'],
+ [0x9240, '叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄'],
+ [0x9280, '逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓'],
+ [0x9340, '邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬'],
+ [0x9380, '凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入'],
+ [0x9440, '如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅'],
+ [0x9480, '楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美'],
+ [0x9540, '鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷'],
+ [0x9580, '斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋'],
+ [0x9640, '法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆'],
+ [0x9680, '摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒'],
+ [0x9740, '諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲'],
+ [0x9780, '沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯'],
+ [0x9840, '蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕'],
+ [0x989f, '弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲'],
+ [0x9940, '僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭'],
+ [0x9980, '凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨'],
+ [0x9a40, '咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸'],
+ [0x9a80, '噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩'],
+ [0x9b40, '奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀'],
+ [0x9b80, '它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏'],
+ [0x9c40, '廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠'],
+ [0x9c80, '怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛'],
+ [0x9d40, '戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫'],
+ [0x9d80, '捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼'],
+ [0x9e40, '曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎'],
+ [0x9e80, '梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣'],
+ [0x9f40, '檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯'],
+ [0x9f80, '麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌'],
+ [0xe040, '漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝'],
+ [0xe080, '烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱'],
+ [0xe140, '瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿'],
+ [0xe180, '痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬'],
+ [0xe240, '磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰'],
+ [0xe280, '窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆'],
+ [0xe340, '紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷'],
+ [0xe380, '縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋'],
+ [0xe440, '隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤'],
+ [0xe480, '艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈'],
+ [0xe540, '蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬'],
+ [0xe580, '蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞'],
+ [0xe640, '襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧'],
+ [0xe680, '諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊'],
+ [0xe740, '蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜'],
+ [0xe780, '轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮'],
+ [0xe840, '錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙'],
+ [0xe880, '閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰'],
+ [0xe940, '顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃'],
+ [0xe980, '騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈'],
+ [0xea40, '鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯'],
+ [0xea80, '黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠堯槇遙瑤凜熙']
+]
+
+module.exports = function toSJIS (utf8Char) {
+ if (!utf8Char || utf8Char === '') return
+
+ for (let i = 0; i < SJIS_UTF8.length; i++) {
+ const kanji = SJIS_UTF8[i][1]
+
+ const posIndex = kanji.indexOf(utf8Char)
+ if (posIndex >= 0) {
+ return SJIS_UTF8[i][0] + posIndex
+ }
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/browser.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..dc8a9998249e4d8814b38732190c7ed2bbc3b6aa
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/browser.js
@@ -0,0 +1,76 @@
+
+const canPromise = require('./can-promise')
+
+const QRCode = require('./core/qrcode')
+const CanvasRenderer = require('./renderer/canvas')
+const SvgRenderer = require('./renderer/svg-tag.js')
+
+function renderCanvas (renderFunc, canvas, text, opts, cb) {
+ const args = [].slice.call(arguments, 1)
+ const argsNum = args.length
+ const isLastArgCb = typeof args[argsNum - 1] === 'function'
+
+ if (!isLastArgCb && !canPromise()) {
+ throw new Error('Callback required as last argument')
+ }
+
+ if (isLastArgCb) {
+ if (argsNum < 2) {
+ throw new Error('Too few arguments provided')
+ }
+
+ if (argsNum === 2) {
+ cb = text
+ text = canvas
+ canvas = opts = undefined
+ } else if (argsNum === 3) {
+ if (canvas.getContext && typeof cb === 'undefined') {
+ cb = opts
+ opts = undefined
+ } else {
+ cb = opts
+ opts = text
+ text = canvas
+ canvas = undefined
+ }
+ }
+ } else {
+ if (argsNum < 1) {
+ throw new Error('Too few arguments provided')
+ }
+
+ if (argsNum === 1) {
+ text = canvas
+ canvas = opts = undefined
+ } else if (argsNum === 2 && !canvas.getContext) {
+ opts = text
+ text = canvas
+ canvas = undefined
+ }
+
+ return new Promise(function (resolve, reject) {
+ try {
+ const data = QRCode.create(text, opts)
+ resolve(renderFunc(data, canvas, opts))
+ } catch (e) {
+ reject(e)
+ }
+ })
+ }
+
+ try {
+ const data = QRCode.create(text, opts)
+ cb(null, renderFunc(data, canvas, opts))
+ } catch (e) {
+ cb(e)
+ }
+}
+
+exports.create = QRCode.create
+exports.toCanvas = renderCanvas.bind(null, CanvasRenderer.render)
+exports.toDataURL = renderCanvas.bind(null, CanvasRenderer.renderToDataURL)
+
+// only svg for now.
+exports.toString = renderCanvas.bind(null, function (data, _, opts) {
+ return SvgRenderer.render(data, opts)
+})
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/can-promise.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/can-promise.js
new file mode 100644
index 0000000000000000000000000000000000000000..77267f159f74300e1f884996e18dd67ef0b430c2
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/can-promise.js
@@ -0,0 +1,7 @@
+// can-promise has a crash in some versions of react native that dont have
+// standard global objects
+// https://github.com/soldair/node-qrcode/issues/157
+
+module.exports = function () {
+ return typeof Promise === 'function' && Promise.prototype && Promise.prototype.then
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alignment-pattern.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alignment-pattern.js
new file mode 100644
index 0000000000000000000000000000000000000000..63c3154e976ca3894f16ebe60e9ead0f448c7ee1
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alignment-pattern.js
@@ -0,0 +1,83 @@
+/**
+ * Alignment pattern are fixed reference pattern in defined positions
+ * in a matrix symbology, which enables the decode software to re-synchronise
+ * the coordinate mapping of the image modules in the event of moderate amounts
+ * of distortion of the image.
+ *
+ * Alignment patterns are present only in QR Code symbols of version 2 or larger
+ * and their number depends on the symbol version.
+ */
+
+const getSymbolSize = require('./utils').getSymbolSize
+
+/**
+ * Calculate the row/column coordinates of the center module of each alignment pattern
+ * for the specified QR Code version.
+ *
+ * The alignment patterns are positioned symmetrically on either side of the diagonal
+ * running from the top left corner of the symbol to the bottom right corner.
+ *
+ * Since positions are simmetrical only half of the coordinates are returned.
+ * Each item of the array will represent in turn the x and y coordinate.
+ * @see {@link getPositions}
+ *
+ * @param {Number} version QR Code version
+ * @return {Array} Array of coordinate
+ */
+exports.getRowColCoords = function getRowColCoords (version) {
+ if (version === 1) return []
+
+ const posCount = Math.floor(version / 7) + 2
+ const size = getSymbolSize(version)
+ const intervals = size === 145 ? 26 : Math.ceil((size - 13) / (2 * posCount - 2)) * 2
+ const positions = [size - 7] // Last coord is always (size - 7)
+
+ for (let i = 1; i < posCount - 1; i++) {
+ positions[i] = positions[i - 1] - intervals
+ }
+
+ positions.push(6) // First coord is always 6
+
+ return positions.reverse()
+}
+
+/**
+ * Returns an array containing the positions of each alignment pattern.
+ * Each array's element represent the center point of the pattern as (x, y) coordinates
+ *
+ * Coordinates are calculated expanding the row/column coordinates returned by {@link getRowColCoords}
+ * and filtering out the items that overlaps with finder pattern
+ *
+ * @example
+ * For a Version 7 symbol {@link getRowColCoords} returns values 6, 22 and 38.
+ * The alignment patterns, therefore, are to be centered on (row, column)
+ * positions (6,22), (22,6), (22,22), (22,38), (38,22), (38,38).
+ * Note that the coordinates (6,6), (6,38), (38,6) are occupied by finder patterns
+ * and are not therefore used for alignment patterns.
+ *
+ * let pos = getPositions(7)
+ * // [[6,22], [22,6], [22,22], [22,38], [38,22], [38,38]]
+ *
+ * @param {Number} version QR Code version
+ * @return {Array} Array of coordinates
+ */
+exports.getPositions = function getPositions (version) {
+ const coords = []
+ const pos = exports.getRowColCoords(version)
+ const posLength = pos.length
+
+ for (let i = 0; i < posLength; i++) {
+ for (let j = 0; j < posLength; j++) {
+ // Skip if position is occupied by finder patterns
+ if ((i === 0 && j === 0) || // top-left
+ (i === 0 && j === posLength - 1) || // bottom-left
+ (i === posLength - 1 && j === 0)) { // top-right
+ continue
+ }
+
+ coords.push([pos[i], pos[j]])
+ }
+ }
+
+ return coords
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alphanumeric-data.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alphanumeric-data.js
new file mode 100644
index 0000000000000000000000000000000000000000..29ddf50c3ad1f02beb0f8dc79f6b10e3d207ea36
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/alphanumeric-data.js
@@ -0,0 +1,59 @@
+const Mode = require('./mode')
+
+/**
+ * Array of characters available in alphanumeric mode
+ *
+ * As per QR Code specification, to each character
+ * is assigned a value from 0 to 44 which in this case coincides
+ * with the array index
+ *
+ * @type {Array}
+ */
+const ALPHA_NUM_CHARS = [
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ' ', '$', '%', '*', '+', '-', '.', '/', ':'
+]
+
+function AlphanumericData (data) {
+ this.mode = Mode.ALPHANUMERIC
+ this.data = data
+}
+
+AlphanumericData.getBitsLength = function getBitsLength (length) {
+ return 11 * Math.floor(length / 2) + 6 * (length % 2)
+}
+
+AlphanumericData.prototype.getLength = function getLength () {
+ return this.data.length
+}
+
+AlphanumericData.prototype.getBitsLength = function getBitsLength () {
+ return AlphanumericData.getBitsLength(this.data.length)
+}
+
+AlphanumericData.prototype.write = function write (bitBuffer) {
+ let i
+
+ // Input data characters are divided into groups of two characters
+ // and encoded as 11-bit binary codes.
+ for (i = 0; i + 2 <= this.data.length; i += 2) {
+ // The character value of the first character is multiplied by 45
+ let value = ALPHA_NUM_CHARS.indexOf(this.data[i]) * 45
+
+ // The character value of the second digit is added to the product
+ value += ALPHA_NUM_CHARS.indexOf(this.data[i + 1])
+
+ // The sum is then stored as 11-bit binary number
+ bitBuffer.put(value, 11)
+ }
+
+ // If the number of input data characters is not a multiple of two,
+ // the character value of the final character is encoded as a 6-bit binary number.
+ if (this.data.length % 2) {
+ bitBuffer.put(ALPHA_NUM_CHARS.indexOf(this.data[i]), 6)
+ }
+}
+
+module.exports = AlphanumericData
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-buffer.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-buffer.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b41d3d920ed97d04aabdc7d115302709ca42ae5
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-buffer.js
@@ -0,0 +1,37 @@
+function BitBuffer () {
+ this.buffer = []
+ this.length = 0
+}
+
+BitBuffer.prototype = {
+
+ get: function (index) {
+ const bufIndex = Math.floor(index / 8)
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) === 1
+ },
+
+ put: function (num, length) {
+ for (let i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) === 1)
+ }
+ },
+
+ getLengthInBits: function () {
+ return this.length
+ },
+
+ putBit: function (bit) {
+ const bufIndex = Math.floor(this.length / 8)
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0)
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8))
+ }
+
+ this.length++
+ }
+}
+
+module.exports = BitBuffer
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-matrix.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-matrix.js
new file mode 100644
index 0000000000000000000000000000000000000000..439138b99a746c0f22b432c7bfad608965fea3e9
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/bit-matrix.js
@@ -0,0 +1,65 @@
+/**
+ * Helper class to handle QR Code symbol modules
+ *
+ * @param {Number} size Symbol size
+ */
+function BitMatrix (size) {
+ if (!size || size < 1) {
+ throw new Error('BitMatrix size must be defined and greater than 0')
+ }
+
+ this.size = size
+ this.data = new Uint8Array(size * size)
+ this.reservedBit = new Uint8Array(size * size)
+}
+
+/**
+ * Set bit value at specified location
+ * If reserved flag is set, this bit will be ignored during masking process
+ *
+ * @param {Number} row
+ * @param {Number} col
+ * @param {Boolean} value
+ * @param {Boolean} reserved
+ */
+BitMatrix.prototype.set = function (row, col, value, reserved) {
+ const index = row * this.size + col
+ this.data[index] = value
+ if (reserved) this.reservedBit[index] = true
+}
+
+/**
+ * Returns bit value at specified location
+ *
+ * @param {Number} row
+ * @param {Number} col
+ * @return {Boolean}
+ */
+BitMatrix.prototype.get = function (row, col) {
+ return this.data[row * this.size + col]
+}
+
+/**
+ * Applies xor operator at specified location
+ * (used during masking process)
+ *
+ * @param {Number} row
+ * @param {Number} col
+ * @param {Boolean} value
+ */
+BitMatrix.prototype.xor = function (row, col, value) {
+ this.data[row * this.size + col] ^= value
+}
+
+/**
+ * Check if bit at specified location is reserved
+ *
+ * @param {Number} row
+ * @param {Number} col
+ * @return {Boolean}
+ */
+BitMatrix.prototype.isReserved = function (row, col) {
+ return this.reservedBit[row * this.size + col]
+}
+
+module.exports = BitMatrix
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/byte-data.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/byte-data.js
new file mode 100644
index 0000000000000000000000000000000000000000..289a601fbe9257263bd623eea1a5452e42c6813f
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/byte-data.js
@@ -0,0 +1,30 @@
+const encodeUtf8 = require('encode-utf8')
+const Mode = require('./mode')
+
+function ByteData (data) {
+ this.mode = Mode.BYTE
+ if (typeof (data) === 'string') {
+ data = encodeUtf8(data)
+ }
+ this.data = new Uint8Array(data)
+}
+
+ByteData.getBitsLength = function getBitsLength (length) {
+ return length * 8
+}
+
+ByteData.prototype.getLength = function getLength () {
+ return this.data.length
+}
+
+ByteData.prototype.getBitsLength = function getBitsLength () {
+ return ByteData.getBitsLength(this.data.length)
+}
+
+ByteData.prototype.write = function (bitBuffer) {
+ for (let i = 0, l = this.data.length; i < l; i++) {
+ bitBuffer.put(this.data[i], 8)
+ }
+}
+
+module.exports = ByteData
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-code.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-code.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f2fcebb4fa9c3d10bc4cbb95b1083ea19f83f5a
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-code.js
@@ -0,0 +1,135 @@
+const ECLevel = require('./error-correction-level')
+
+const EC_BLOCKS_TABLE = [
+// L M Q H
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 2, 2,
+ 1, 2, 2, 4,
+ 1, 2, 4, 4,
+ 2, 4, 4, 4,
+ 2, 4, 6, 5,
+ 2, 4, 6, 6,
+ 2, 5, 8, 8,
+ 4, 5, 8, 8,
+ 4, 5, 8, 11,
+ 4, 8, 10, 11,
+ 4, 9, 12, 16,
+ 4, 9, 16, 16,
+ 6, 10, 12, 18,
+ 6, 10, 17, 16,
+ 6, 11, 16, 19,
+ 6, 13, 18, 21,
+ 7, 14, 21, 25,
+ 8, 16, 20, 25,
+ 8, 17, 23, 25,
+ 9, 17, 23, 34,
+ 9, 18, 25, 30,
+ 10, 20, 27, 32,
+ 12, 21, 29, 35,
+ 12, 23, 34, 37,
+ 12, 25, 34, 40,
+ 13, 26, 35, 42,
+ 14, 28, 38, 45,
+ 15, 29, 40, 48,
+ 16, 31, 43, 51,
+ 17, 33, 45, 54,
+ 18, 35, 48, 57,
+ 19, 37, 51, 60,
+ 19, 38, 53, 63,
+ 20, 40, 56, 66,
+ 21, 43, 59, 70,
+ 22, 45, 62, 74,
+ 24, 47, 65, 77,
+ 25, 49, 68, 81
+]
+
+const EC_CODEWORDS_TABLE = [
+// L M Q H
+ 7, 10, 13, 17,
+ 10, 16, 22, 28,
+ 15, 26, 36, 44,
+ 20, 36, 52, 64,
+ 26, 48, 72, 88,
+ 36, 64, 96, 112,
+ 40, 72, 108, 130,
+ 48, 88, 132, 156,
+ 60, 110, 160, 192,
+ 72, 130, 192, 224,
+ 80, 150, 224, 264,
+ 96, 176, 260, 308,
+ 104, 198, 288, 352,
+ 120, 216, 320, 384,
+ 132, 240, 360, 432,
+ 144, 280, 408, 480,
+ 168, 308, 448, 532,
+ 180, 338, 504, 588,
+ 196, 364, 546, 650,
+ 224, 416, 600, 700,
+ 224, 442, 644, 750,
+ 252, 476, 690, 816,
+ 270, 504, 750, 900,
+ 300, 560, 810, 960,
+ 312, 588, 870, 1050,
+ 336, 644, 952, 1110,
+ 360, 700, 1020, 1200,
+ 390, 728, 1050, 1260,
+ 420, 784, 1140, 1350,
+ 450, 812, 1200, 1440,
+ 480, 868, 1290, 1530,
+ 510, 924, 1350, 1620,
+ 540, 980, 1440, 1710,
+ 570, 1036, 1530, 1800,
+ 570, 1064, 1590, 1890,
+ 600, 1120, 1680, 1980,
+ 630, 1204, 1770, 2100,
+ 660, 1260, 1860, 2220,
+ 720, 1316, 1950, 2310,
+ 750, 1372, 2040, 2430
+]
+
+/**
+ * Returns the number of error correction block that the QR Code should contain
+ * for the specified version and error correction level.
+ *
+ * @param {Number} version QR Code version
+ * @param {Number} errorCorrectionLevel Error correction level
+ * @return {Number} Number of error correction blocks
+ */
+exports.getBlocksCount = function getBlocksCount (version, errorCorrectionLevel) {
+ switch (errorCorrectionLevel) {
+ case ECLevel.L:
+ return EC_BLOCKS_TABLE[(version - 1) * 4 + 0]
+ case ECLevel.M:
+ return EC_BLOCKS_TABLE[(version - 1) * 4 + 1]
+ case ECLevel.Q:
+ return EC_BLOCKS_TABLE[(version - 1) * 4 + 2]
+ case ECLevel.H:
+ return EC_BLOCKS_TABLE[(version - 1) * 4 + 3]
+ default:
+ return undefined
+ }
+}
+
+/**
+ * Returns the number of error correction codewords to use for the specified
+ * version and error correction level.
+ *
+ * @param {Number} version QR Code version
+ * @param {Number} errorCorrectionLevel Error correction level
+ * @return {Number} Number of error correction codewords
+ */
+exports.getTotalCodewordsCount = function getTotalCodewordsCount (version, errorCorrectionLevel) {
+ switch (errorCorrectionLevel) {
+ case ECLevel.L:
+ return EC_CODEWORDS_TABLE[(version - 1) * 4 + 0]
+ case ECLevel.M:
+ return EC_CODEWORDS_TABLE[(version - 1) * 4 + 1]
+ case ECLevel.Q:
+ return EC_CODEWORDS_TABLE[(version - 1) * 4 + 2]
+ case ECLevel.H:
+ return EC_CODEWORDS_TABLE[(version - 1) * 4 + 3]
+ default:
+ return undefined
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-level.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-level.js
new file mode 100644
index 0000000000000000000000000000000000000000..07433d6bff7692d37f5747976545150a8893f0da
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/error-correction-level.js
@@ -0,0 +1,50 @@
+exports.L = { bit: 1 }
+exports.M = { bit: 0 }
+exports.Q = { bit: 3 }
+exports.H = { bit: 2 }
+
+function fromString (string) {
+ if (typeof string !== 'string') {
+ throw new Error('Param is not a string')
+ }
+
+ const lcStr = string.toLowerCase()
+
+ switch (lcStr) {
+ case 'l':
+ case 'low':
+ return exports.L
+
+ case 'm':
+ case 'medium':
+ return exports.M
+
+ case 'q':
+ case 'quartile':
+ return exports.Q
+
+ case 'h':
+ case 'high':
+ return exports.H
+
+ default:
+ throw new Error('Unknown EC Level: ' + string)
+ }
+}
+
+exports.isValid = function isValid (level) {
+ return level && typeof level.bit !== 'undefined' &&
+ level.bit >= 0 && level.bit < 4
+}
+
+exports.from = function from (value, defaultValue) {
+ if (exports.isValid(value)) {
+ return value
+ }
+
+ try {
+ return fromString(value)
+ } catch (e) {
+ return defaultValue
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/finder-pattern.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/finder-pattern.js
new file mode 100644
index 0000000000000000000000000000000000000000..4613c041a972ea603b56deda6b85488c44ba1443
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/finder-pattern.js
@@ -0,0 +1,22 @@
+const getSymbolSize = require('./utils').getSymbolSize
+const FINDER_PATTERN_SIZE = 7
+
+/**
+ * Returns an array containing the positions of each finder pattern.
+ * Each array's element represent the top-left point of the pattern as (x, y) coordinates
+ *
+ * @param {Number} version QR Code version
+ * @return {Array} Array of coordinates
+ */
+exports.getPositions = function getPositions (version) {
+ const size = getSymbolSize(version)
+
+ return [
+ // top-left
+ [0, 0],
+ // top-right
+ [size - FINDER_PATTERN_SIZE, 0],
+ // bottom-left
+ [0, size - FINDER_PATTERN_SIZE]
+ ]
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/format-info.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/format-info.js
new file mode 100644
index 0000000000000000000000000000000000000000..11fe9efaacdd292fb39698e341e0df3ef8fe95e7
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/format-info.js
@@ -0,0 +1,29 @@
+const Utils = require('./utils')
+
+const G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0)
+const G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)
+const G15_BCH = Utils.getBCHDigit(G15)
+
+/**
+ * Returns format information with relative error correction bits
+ *
+ * The format information is a 15-bit sequence containing 5 data bits,
+ * with 10 error correction bits calculated using the (15, 5) BCH code.
+ *
+ * @param {Number} errorCorrectionLevel Error correction level
+ * @param {Number} mask Mask pattern
+ * @return {Number} Encoded format information bits
+ */
+exports.getEncodedBits = function getEncodedBits (errorCorrectionLevel, mask) {
+ const data = ((errorCorrectionLevel.bit << 3) | mask)
+ let d = data << 10
+
+ while (Utils.getBCHDigit(d) - G15_BCH >= 0) {
+ d ^= (G15 << (Utils.getBCHDigit(d) - G15_BCH))
+ }
+
+ // xor final data with mask pattern in order to ensure that
+ // no combination of Error Correction Level and data mask pattern
+ // will result in an all-zero data string
+ return ((data << 10) | d) ^ G15_MASK
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/galois-field.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/galois-field.js
new file mode 100644
index 0000000000000000000000000000000000000000..8125179c058e1b130c551dc04c12e3292311e751
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/galois-field.js
@@ -0,0 +1,69 @@
+const EXP_TABLE = new Uint8Array(512)
+const LOG_TABLE = new Uint8Array(256)
+/**
+ * Precompute the log and anti-log tables for faster computation later
+ *
+ * For each possible value in the galois field 2^8, we will pre-compute
+ * the logarithm and anti-logarithm (exponential) of this value
+ *
+ * ref {@link https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#Introduction_to_mathematical_fields}
+ */
+;(function initTables () {
+ let x = 1
+ for (let i = 0; i < 255; i++) {
+ EXP_TABLE[i] = x
+ LOG_TABLE[x] = i
+
+ x <<= 1 // multiply by 2
+
+ // The QR code specification says to use byte-wise modulo 100011101 arithmetic.
+ // This means that when a number is 256 or larger, it should be XORed with 0x11D.
+ if (x & 0x100) { // similar to x >= 256, but a lot faster (because 0x100 == 256)
+ x ^= 0x11D
+ }
+ }
+
+ // Optimization: double the size of the anti-log table so that we don't need to mod 255 to
+ // stay inside the bounds (because we will mainly use this table for the multiplication of
+ // two GF numbers, no more).
+ // @see {@link mul}
+ for (let i = 255; i < 512; i++) {
+ EXP_TABLE[i] = EXP_TABLE[i - 255]
+ }
+}())
+
+/**
+ * Returns log value of n inside Galois Field
+ *
+ * @param {Number} n
+ * @return {Number}
+ */
+exports.log = function log (n) {
+ if (n < 1) throw new Error('log(' + n + ')')
+ return LOG_TABLE[n]
+}
+
+/**
+ * Returns anti-log value of n inside Galois Field
+ *
+ * @param {Number} n
+ * @return {Number}
+ */
+exports.exp = function exp (n) {
+ return EXP_TABLE[n]
+}
+
+/**
+ * Multiplies two number inside Galois Field
+ *
+ * @param {Number} x
+ * @param {Number} y
+ * @return {Number}
+ */
+exports.mul = function mul (x, y) {
+ if (x === 0 || y === 0) return 0
+
+ // should be EXP_TABLE[(LOG_TABLE[x] + LOG_TABLE[y]) % 255] if EXP_TABLE wasn't oversized
+ // @see {@link initTables}
+ return EXP_TABLE[LOG_TABLE[x] + LOG_TABLE[y]]
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/kanji-data.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/kanji-data.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1d9a6922d8e91cd90d89ea301d2531145b129f2
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/kanji-data.js
@@ -0,0 +1,54 @@
+const Mode = require('./mode')
+const Utils = require('./utils')
+
+function KanjiData (data) {
+ this.mode = Mode.KANJI
+ this.data = data
+}
+
+KanjiData.getBitsLength = function getBitsLength (length) {
+ return length * 13
+}
+
+KanjiData.prototype.getLength = function getLength () {
+ return this.data.length
+}
+
+KanjiData.prototype.getBitsLength = function getBitsLength () {
+ return KanjiData.getBitsLength(this.data.length)
+}
+
+KanjiData.prototype.write = function (bitBuffer) {
+ let i
+
+ // In the Shift JIS system, Kanji characters are represented by a two byte combination.
+ // These byte values are shifted from the JIS X 0208 values.
+ // JIS X 0208 gives details of the shift coded representation.
+ for (i = 0; i < this.data.length; i++) {
+ let value = Utils.toSJIS(this.data[i])
+
+ // For characters with Shift JIS values from 0x8140 to 0x9FFC:
+ if (value >= 0x8140 && value <= 0x9FFC) {
+ // Subtract 0x8140 from Shift JIS value
+ value -= 0x8140
+
+ // For characters with Shift JIS values from 0xE040 to 0xEBBF
+ } else if (value >= 0xE040 && value <= 0xEBBF) {
+ // Subtract 0xC140 from Shift JIS value
+ value -= 0xC140
+ } else {
+ throw new Error(
+ 'Invalid SJIS character: ' + this.data[i] + '\n' +
+ 'Make sure your charset is UTF-8')
+ }
+
+ // Multiply most significant byte of result by 0xC0
+ // and add least significant byte to product
+ value = (((value >>> 8) & 0xff) * 0xC0) + (value & 0xff)
+
+ // Convert result to a 13-bit binary string
+ bitBuffer.put(value, 13)
+ }
+}
+
+module.exports = KanjiData
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mask-pattern.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mask-pattern.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5f8900eb19c94a30b74d795177f1d3fa32184d9
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mask-pattern.js
@@ -0,0 +1,234 @@
+/**
+ * Data mask pattern reference
+ * @type {Object}
+ */
+exports.Patterns = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+}
+
+/**
+ * Weighted penalty scores for the undesirable features
+ * @type {Object}
+ */
+const PenaltyScores = {
+ N1: 3,
+ N2: 3,
+ N3: 40,
+ N4: 10
+}
+
+/**
+ * Check if mask pattern value is valid
+ *
+ * @param {Number} mask Mask pattern
+ * @return {Boolean} true if valid, false otherwise
+ */
+exports.isValid = function isValid (mask) {
+ return mask != null && mask !== '' && !isNaN(mask) && mask >= 0 && mask <= 7
+}
+
+/**
+ * Returns mask pattern from a value.
+ * If value is not valid, returns undefined
+ *
+ * @param {Number|String} value Mask pattern value
+ * @return {Number} Valid mask pattern or undefined
+ */
+exports.from = function from (value) {
+ return exports.isValid(value) ? parseInt(value, 10) : undefined
+}
+
+/**
+* Find adjacent modules in row/column with the same color
+* and assign a penalty value.
+*
+* Points: N1 + i
+* i is the amount by which the number of adjacent modules of the same color exceeds 5
+*/
+exports.getPenaltyN1 = function getPenaltyN1 (data) {
+ const size = data.size
+ let points = 0
+ let sameCountCol = 0
+ let sameCountRow = 0
+ let lastCol = null
+ let lastRow = null
+
+ for (let row = 0; row < size; row++) {
+ sameCountCol = sameCountRow = 0
+ lastCol = lastRow = null
+
+ for (let col = 0; col < size; col++) {
+ let module = data.get(row, col)
+ if (module === lastCol) {
+ sameCountCol++
+ } else {
+ if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5)
+ lastCol = module
+ sameCountCol = 1
+ }
+
+ module = data.get(col, row)
+ if (module === lastRow) {
+ sameCountRow++
+ } else {
+ if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5)
+ lastRow = module
+ sameCountRow = 1
+ }
+ }
+
+ if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5)
+ if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5)
+ }
+
+ return points
+}
+
+/**
+ * Find 2x2 blocks with the same color and assign a penalty value
+ *
+ * Points: N2 * (m - 1) * (n - 1)
+ */
+exports.getPenaltyN2 = function getPenaltyN2 (data) {
+ const size = data.size
+ let points = 0
+
+ for (let row = 0; row < size - 1; row++) {
+ for (let col = 0; col < size - 1; col++) {
+ const last = data.get(row, col) +
+ data.get(row, col + 1) +
+ data.get(row + 1, col) +
+ data.get(row + 1, col + 1)
+
+ if (last === 4 || last === 0) points++
+ }
+ }
+
+ return points * PenaltyScores.N2
+}
+
+/**
+ * Find 1:1:3:1:1 ratio (dark:light:dark:light:dark) pattern in row/column,
+ * preceded or followed by light area 4 modules wide
+ *
+ * Points: N3 * number of pattern found
+ */
+exports.getPenaltyN3 = function getPenaltyN3 (data) {
+ const size = data.size
+ let points = 0
+ let bitsCol = 0
+ let bitsRow = 0
+
+ for (let row = 0; row < size; row++) {
+ bitsCol = bitsRow = 0
+ for (let col = 0; col < size; col++) {
+ bitsCol = ((bitsCol << 1) & 0x7FF) | data.get(row, col)
+ if (col >= 10 && (bitsCol === 0x5D0 || bitsCol === 0x05D)) points++
+
+ bitsRow = ((bitsRow << 1) & 0x7FF) | data.get(col, row)
+ if (col >= 10 && (bitsRow === 0x5D0 || bitsRow === 0x05D)) points++
+ }
+ }
+
+ return points * PenaltyScores.N3
+}
+
+/**
+ * Calculate proportion of dark modules in entire symbol
+ *
+ * Points: N4 * k
+ *
+ * k is the rating of the deviation of the proportion of dark modules
+ * in the symbol from 50% in steps of 5%
+ */
+exports.getPenaltyN4 = function getPenaltyN4 (data) {
+ let darkCount = 0
+ const modulesCount = data.data.length
+
+ for (let i = 0; i < modulesCount; i++) darkCount += data.data[i]
+
+ const k = Math.abs(Math.ceil((darkCount * 100 / modulesCount) / 5) - 10)
+
+ return k * PenaltyScores.N4
+}
+
+/**
+ * Return mask value at given position
+ *
+ * @param {Number} maskPattern Pattern reference value
+ * @param {Number} i Row
+ * @param {Number} j Column
+ * @return {Boolean} Mask value
+ */
+function getMaskAt (maskPattern, i, j) {
+ switch (maskPattern) {
+ case exports.Patterns.PATTERN000: return (i + j) % 2 === 0
+ case exports.Patterns.PATTERN001: return i % 2 === 0
+ case exports.Patterns.PATTERN010: return j % 3 === 0
+ case exports.Patterns.PATTERN011: return (i + j) % 3 === 0
+ case exports.Patterns.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0
+ case exports.Patterns.PATTERN101: return (i * j) % 2 + (i * j) % 3 === 0
+ case exports.Patterns.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 === 0
+ case exports.Patterns.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 === 0
+
+ default: throw new Error('bad maskPattern:' + maskPattern)
+ }
+}
+
+/**
+ * Apply a mask pattern to a BitMatrix
+ *
+ * @param {Number} pattern Pattern reference number
+ * @param {BitMatrix} data BitMatrix data
+ */
+exports.applyMask = function applyMask (pattern, data) {
+ const size = data.size
+
+ for (let col = 0; col < size; col++) {
+ for (let row = 0; row < size; row++) {
+ if (data.isReserved(row, col)) continue
+ data.xor(row, col, getMaskAt(pattern, row, col))
+ }
+ }
+}
+
+/**
+ * Returns the best mask pattern for data
+ *
+ * @param {BitMatrix} data
+ * @return {Number} Mask pattern reference number
+ */
+exports.getBestMask = function getBestMask (data, setupFormatFunc) {
+ const numPatterns = Object.keys(exports.Patterns).length
+ let bestPattern = 0
+ let lowerPenalty = Infinity
+
+ for (let p = 0; p < numPatterns; p++) {
+ setupFormatFunc(p)
+ exports.applyMask(p, data)
+
+ // Calculate penalty
+ const penalty =
+ exports.getPenaltyN1(data) +
+ exports.getPenaltyN2(data) +
+ exports.getPenaltyN3(data) +
+ exports.getPenaltyN4(data)
+
+ // Undo previously applied mask
+ exports.applyMask(p, data)
+
+ if (penalty < lowerPenalty) {
+ lowerPenalty = penalty
+ bestPattern = p
+ }
+ }
+
+ return bestPattern
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mode.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mode.js
new file mode 100644
index 0000000000000000000000000000000000000000..fd95a6ef72b2414042cb9cf73fd7f4fe7ce054fe
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/mode.js
@@ -0,0 +1,167 @@
+const VersionCheck = require('./version-check')
+const Regex = require('./regex')
+
+/**
+ * Numeric mode encodes data from the decimal digit set (0 - 9)
+ * (byte values 30HEX to 39HEX).
+ * Normally, 3 data characters are represented by 10 bits.
+ *
+ * @type {Object}
+ */
+exports.NUMERIC = {
+ id: 'Numeric',
+ bit: 1 << 0,
+ ccBits: [10, 12, 14]
+}
+
+/**
+ * Alphanumeric mode encodes data from a set of 45 characters,
+ * i.e. 10 numeric digits (0 - 9),
+ * 26 alphabetic characters (A - Z),
+ * and 9 symbols (SP, $, %, *, +, -, ., /, :).
+ * Normally, two input characters are represented by 11 bits.
+ *
+ * @type {Object}
+ */
+exports.ALPHANUMERIC = {
+ id: 'Alphanumeric',
+ bit: 1 << 1,
+ ccBits: [9, 11, 13]
+}
+
+/**
+ * In byte mode, data is encoded at 8 bits per character.
+ *
+ * @type {Object}
+ */
+exports.BYTE = {
+ id: 'Byte',
+ bit: 1 << 2,
+ ccBits: [8, 16, 16]
+}
+
+/**
+ * The Kanji mode efficiently encodes Kanji characters in accordance with
+ * the Shift JIS system based on JIS X 0208.
+ * The Shift JIS values are shifted from the JIS X 0208 values.
+ * JIS X 0208 gives details of the shift coded representation.
+ * Each two-byte character value is compacted to a 13-bit binary codeword.
+ *
+ * @type {Object}
+ */
+exports.KANJI = {
+ id: 'Kanji',
+ bit: 1 << 3,
+ ccBits: [8, 10, 12]
+}
+
+/**
+ * Mixed mode will contain a sequences of data in a combination of any of
+ * the modes described above
+ *
+ * @type {Object}
+ */
+exports.MIXED = {
+ bit: -1
+}
+
+/**
+ * Returns the number of bits needed to store the data length
+ * according to QR Code specifications.
+ *
+ * @param {Mode} mode Data mode
+ * @param {Number} version QR Code version
+ * @return {Number} Number of bits
+ */
+exports.getCharCountIndicator = function getCharCountIndicator (mode, version) {
+ if (!mode.ccBits) throw new Error('Invalid mode: ' + mode)
+
+ if (!VersionCheck.isValid(version)) {
+ throw new Error('Invalid version: ' + version)
+ }
+
+ if (version >= 1 && version < 10) return mode.ccBits[0]
+ else if (version < 27) return mode.ccBits[1]
+ return mode.ccBits[2]
+}
+
+/**
+ * Returns the most efficient mode to store the specified data
+ *
+ * @param {String} dataStr Input data string
+ * @return {Mode} Best mode
+ */
+exports.getBestModeForData = function getBestModeForData (dataStr) {
+ if (Regex.testNumeric(dataStr)) return exports.NUMERIC
+ else if (Regex.testAlphanumeric(dataStr)) return exports.ALPHANUMERIC
+ else if (Regex.testKanji(dataStr)) return exports.KANJI
+ else return exports.BYTE
+}
+
+/**
+ * Return mode name as string
+ *
+ * @param {Mode} mode Mode object
+ * @returns {String} Mode name
+ */
+exports.toString = function toString (mode) {
+ if (mode && mode.id) return mode.id
+ throw new Error('Invalid mode')
+}
+
+/**
+ * Check if input param is a valid mode object
+ *
+ * @param {Mode} mode Mode object
+ * @returns {Boolean} True if valid mode, false otherwise
+ */
+exports.isValid = function isValid (mode) {
+ return mode && mode.bit && mode.ccBits
+}
+
+/**
+ * Get mode object from its name
+ *
+ * @param {String} string Mode name
+ * @returns {Mode} Mode object
+ */
+function fromString (string) {
+ if (typeof string !== 'string') {
+ throw new Error('Param is not a string')
+ }
+
+ const lcStr = string.toLowerCase()
+
+ switch (lcStr) {
+ case 'numeric':
+ return exports.NUMERIC
+ case 'alphanumeric':
+ return exports.ALPHANUMERIC
+ case 'kanji':
+ return exports.KANJI
+ case 'byte':
+ return exports.BYTE
+ default:
+ throw new Error('Unknown mode: ' + string)
+ }
+}
+
+/**
+ * Returns mode from a value.
+ * If value is not a valid mode, returns defaultValue
+ *
+ * @param {Mode|String} value Encoding mode
+ * @param {Mode} defaultValue Fallback value
+ * @return {Mode} Encoding mode
+ */
+exports.from = function from (value, defaultValue) {
+ if (exports.isValid(value)) {
+ return value
+ }
+
+ try {
+ return fromString(value)
+ } catch (e) {
+ return defaultValue
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/numeric-data.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/numeric-data.js
new file mode 100644
index 0000000000000000000000000000000000000000..5223991c6a7378509b5ab9701fb31e28c68c6faf
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/numeric-data.js
@@ -0,0 +1,43 @@
+const Mode = require('./mode')
+
+function NumericData (data) {
+ this.mode = Mode.NUMERIC
+ this.data = data.toString()
+}
+
+NumericData.getBitsLength = function getBitsLength (length) {
+ return 10 * Math.floor(length / 3) + ((length % 3) ? ((length % 3) * 3 + 1) : 0)
+}
+
+NumericData.prototype.getLength = function getLength () {
+ return this.data.length
+}
+
+NumericData.prototype.getBitsLength = function getBitsLength () {
+ return NumericData.getBitsLength(this.data.length)
+}
+
+NumericData.prototype.write = function write (bitBuffer) {
+ let i, group, value
+
+ // The input data string is divided into groups of three digits,
+ // and each group is converted to its 10-bit binary equivalent.
+ for (i = 0; i + 3 <= this.data.length; i += 3) {
+ group = this.data.substr(i, 3)
+ value = parseInt(group, 10)
+
+ bitBuffer.put(value, 10)
+ }
+
+ // If the number of input digits is not an exact multiple of three,
+ // the final one or two digits are converted to 4 or 7 bits respectively.
+ const remainingNum = this.data.length - i
+ if (remainingNum > 0) {
+ group = this.data.substr(i)
+ value = parseInt(group, 10)
+
+ bitBuffer.put(value, remainingNum * 3 + 1)
+ }
+}
+
+module.exports = NumericData
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/polynomial.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/polynomial.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6ed9c2e9173b5e494d488e99b72e03eb55fcd2f
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/polynomial.js
@@ -0,0 +1,62 @@
+const GF = require('./galois-field')
+
+/**
+ * Multiplies two polynomials inside Galois Field
+ *
+ * @param {Uint8Array} p1 Polynomial
+ * @param {Uint8Array} p2 Polynomial
+ * @return {Uint8Array} Product of p1 and p2
+ */
+exports.mul = function mul (p1, p2) {
+ const coeff = new Uint8Array(p1.length + p2.length - 1)
+
+ for (let i = 0; i < p1.length; i++) {
+ for (let j = 0; j < p2.length; j++) {
+ coeff[i + j] ^= GF.mul(p1[i], p2[j])
+ }
+ }
+
+ return coeff
+}
+
+/**
+ * Calculate the remainder of polynomials division
+ *
+ * @param {Uint8Array} divident Polynomial
+ * @param {Uint8Array} divisor Polynomial
+ * @return {Uint8Array} Remainder
+ */
+exports.mod = function mod (divident, divisor) {
+ let result = new Uint8Array(divident)
+
+ while ((result.length - divisor.length) >= 0) {
+ const coeff = result[0]
+
+ for (let i = 0; i < divisor.length; i++) {
+ result[i] ^= GF.mul(divisor[i], coeff)
+ }
+
+ // remove all zeros from buffer head
+ let offset = 0
+ while (offset < result.length && result[offset] === 0) offset++
+ result = result.slice(offset)
+ }
+
+ return result
+}
+
+/**
+ * Generate an irreducible generator polynomial of specified degree
+ * (used by Reed-Solomon encoder)
+ *
+ * @param {Number} degree Degree of the generator polynomial
+ * @return {Uint8Array} Buffer containing polynomial coefficients
+ */
+exports.generateECPolynomial = function generateECPolynomial (degree) {
+ let poly = new Uint8Array([1])
+ for (let i = 0; i < degree; i++) {
+ poly = exports.mul(poly, new Uint8Array([1, GF.exp(i)]))
+ }
+
+ return poly
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/qrcode.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/qrcode.js
new file mode 100644
index 0000000000000000000000000000000000000000..f76df54b3c595e831d70c189e446479dbe8ac75a
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/qrcode.js
@@ -0,0 +1,495 @@
+const Utils = require('./utils')
+const ECLevel = require('./error-correction-level')
+const BitBuffer = require('./bit-buffer')
+const BitMatrix = require('./bit-matrix')
+const AlignmentPattern = require('./alignment-pattern')
+const FinderPattern = require('./finder-pattern')
+const MaskPattern = require('./mask-pattern')
+const ECCode = require('./error-correction-code')
+const ReedSolomonEncoder = require('./reed-solomon-encoder')
+const Version = require('./version')
+const FormatInfo = require('./format-info')
+const Mode = require('./mode')
+const Segments = require('./segments')
+
+/**
+ * QRCode for JavaScript
+ *
+ * modified by Ryan Day for nodejs support
+ * Copyright (c) 2011 Ryan Day
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+//---------------------------------------------------------------------
+// QRCode for JavaScript
+//
+// Copyright (c) 2009 Kazuhiko Arase
+//
+// URL: http://www.d-project.com/
+//
+// Licensed under the MIT license:
+// http://www.opensource.org/licenses/mit-license.php
+//
+// The word "QR Code" is registered trademark of
+// DENSO WAVE INCORPORATED
+// http://www.denso-wave.com/qrcode/faqpatent-e.html
+//
+//---------------------------------------------------------------------
+*/
+
+/**
+ * Add finder patterns bits to matrix
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ * @param {Number} version QR Code version
+ */
+function setupFinderPattern (matrix, version) {
+ const size = matrix.size
+ const pos = FinderPattern.getPositions(version)
+
+ for (let i = 0; i < pos.length; i++) {
+ const row = pos[i][0]
+ const col = pos[i][1]
+
+ for (let r = -1; r <= 7; r++) {
+ if (row + r <= -1 || size <= row + r) continue
+
+ for (let c = -1; c <= 7; c++) {
+ if (col + c <= -1 || size <= col + c) continue
+
+ if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) ||
+ (c >= 0 && c <= 6 && (r === 0 || r === 6)) ||
+ (r >= 2 && r <= 4 && c >= 2 && c <= 4)) {
+ matrix.set(row + r, col + c, true, true)
+ } else {
+ matrix.set(row + r, col + c, false, true)
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Add timing pattern bits to matrix
+ *
+ * Note: this function must be called before {@link setupAlignmentPattern}
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ */
+function setupTimingPattern (matrix) {
+ const size = matrix.size
+
+ for (let r = 8; r < size - 8; r++) {
+ const value = r % 2 === 0
+ matrix.set(r, 6, value, true)
+ matrix.set(6, r, value, true)
+ }
+}
+
+/**
+ * Add alignment patterns bits to matrix
+ *
+ * Note: this function must be called after {@link setupTimingPattern}
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ * @param {Number} version QR Code version
+ */
+function setupAlignmentPattern (matrix, version) {
+ const pos = AlignmentPattern.getPositions(version)
+
+ for (let i = 0; i < pos.length; i++) {
+ const row = pos[i][0]
+ const col = pos[i][1]
+
+ for (let r = -2; r <= 2; r++) {
+ for (let c = -2; c <= 2; c++) {
+ if (r === -2 || r === 2 || c === -2 || c === 2 ||
+ (r === 0 && c === 0)) {
+ matrix.set(row + r, col + c, true, true)
+ } else {
+ matrix.set(row + r, col + c, false, true)
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Add version info bits to matrix
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ * @param {Number} version QR Code version
+ */
+function setupVersionInfo (matrix, version) {
+ const size = matrix.size
+ const bits = Version.getEncodedBits(version)
+ let row, col, mod
+
+ for (let i = 0; i < 18; i++) {
+ row = Math.floor(i / 3)
+ col = i % 3 + size - 8 - 3
+ mod = ((bits >> i) & 1) === 1
+
+ matrix.set(row, col, mod, true)
+ matrix.set(col, row, mod, true)
+ }
+}
+
+/**
+ * Add format info bits to matrix
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
+ * @param {Number} maskPattern Mask pattern reference value
+ */
+function setupFormatInfo (matrix, errorCorrectionLevel, maskPattern) {
+ const size = matrix.size
+ const bits = FormatInfo.getEncodedBits(errorCorrectionLevel, maskPattern)
+ let i, mod
+
+ for (i = 0; i < 15; i++) {
+ mod = ((bits >> i) & 1) === 1
+
+ // vertical
+ if (i < 6) {
+ matrix.set(i, 8, mod, true)
+ } else if (i < 8) {
+ matrix.set(i + 1, 8, mod, true)
+ } else {
+ matrix.set(size - 15 + i, 8, mod, true)
+ }
+
+ // horizontal
+ if (i < 8) {
+ matrix.set(8, size - i - 1, mod, true)
+ } else if (i < 9) {
+ matrix.set(8, 15 - i - 1 + 1, mod, true)
+ } else {
+ matrix.set(8, 15 - i - 1, mod, true)
+ }
+ }
+
+ // fixed module
+ matrix.set(size - 8, 8, 1, true)
+}
+
+/**
+ * Add encoded data bits to matrix
+ *
+ * @param {BitMatrix} matrix Modules matrix
+ * @param {Uint8Array} data Data codewords
+ */
+function setupData (matrix, data) {
+ const size = matrix.size
+ let inc = -1
+ let row = size - 1
+ let bitIndex = 7
+ let byteIndex = 0
+
+ for (let col = size - 1; col > 0; col -= 2) {
+ if (col === 6) col--
+
+ while (true) {
+ for (let c = 0; c < 2; c++) {
+ if (!matrix.isReserved(row, col - c)) {
+ let dark = false
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) === 1)
+ }
+
+ matrix.set(row, col - c, dark)
+ bitIndex--
+
+ if (bitIndex === -1) {
+ byteIndex++
+ bitIndex = 7
+ }
+ }
+ }
+
+ row += inc
+
+ if (row < 0 || size <= row) {
+ row -= inc
+ inc = -inc
+ break
+ }
+ }
+ }
+}
+
+/**
+ * Create encoded codewords from data input
+ *
+ * @param {Number} version QR Code version
+ * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
+ * @param {ByteData} data Data input
+ * @return {Uint8Array} Buffer containing encoded codewords
+ */
+function createData (version, errorCorrectionLevel, segments) {
+ // Prepare data buffer
+ const buffer = new BitBuffer()
+
+ segments.forEach(function (data) {
+ // prefix data with mode indicator (4 bits)
+ buffer.put(data.mode.bit, 4)
+
+ // Prefix data with character count indicator.
+ // The character count indicator is a string of bits that represents the
+ // number of characters that are being encoded.
+ // The character count indicator must be placed after the mode indicator
+ // and must be a certain number of bits long, depending on the QR version
+ // and data mode
+ // @see {@link Mode.getCharCountIndicator}.
+ buffer.put(data.getLength(), Mode.getCharCountIndicator(data.mode, version))
+
+ // add binary data sequence to buffer
+ data.write(buffer)
+ })
+
+ // Calculate required number of bits
+ const totalCodewords = Utils.getSymbolTotalCodewords(version)
+ const ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
+ const dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
+
+ // Add a terminator.
+ // If the bit string is shorter than the total number of required bits,
+ // a terminator of up to four 0s must be added to the right side of the string.
+ // If the bit string is more than four bits shorter than the required number of bits,
+ // add four 0s to the end.
+ if (buffer.getLengthInBits() + 4 <= dataTotalCodewordsBits) {
+ buffer.put(0, 4)
+ }
+
+ // If the bit string is fewer than four bits shorter, add only the number of 0s that
+ // are needed to reach the required number of bits.
+
+ // After adding the terminator, if the number of bits in the string is not a multiple of 8,
+ // pad the string on the right with 0s to make the string's length a multiple of 8.
+ while (buffer.getLengthInBits() % 8 !== 0) {
+ buffer.putBit(0)
+ }
+
+ // Add pad bytes if the string is still shorter than the total number of required bits.
+ // Extend the buffer to fill the data capacity of the symbol corresponding to
+ // the Version and Error Correction Level by adding the Pad Codewords 11101100 (0xEC)
+ // and 00010001 (0x11) alternately.
+ const remainingByte = (dataTotalCodewordsBits - buffer.getLengthInBits()) / 8
+ for (let i = 0; i < remainingByte; i++) {
+ buffer.put(i % 2 ? 0x11 : 0xEC, 8)
+ }
+
+ return createCodewords(buffer, version, errorCorrectionLevel)
+}
+
+/**
+ * Encode input data with Reed-Solomon and return codewords with
+ * relative error correction bits
+ *
+ * @param {BitBuffer} bitBuffer Data to encode
+ * @param {Number} version QR Code version
+ * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
+ * @return {Uint8Array} Buffer containing encoded codewords
+ */
+function createCodewords (bitBuffer, version, errorCorrectionLevel) {
+ // Total codewords for this QR code version (Data + Error correction)
+ const totalCodewords = Utils.getSymbolTotalCodewords(version)
+
+ // Total number of error correction codewords
+ const ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
+
+ // Total number of data codewords
+ const dataTotalCodewords = totalCodewords - ecTotalCodewords
+
+ // Total number of blocks
+ const ecTotalBlocks = ECCode.getBlocksCount(version, errorCorrectionLevel)
+
+ // Calculate how many blocks each group should contain
+ const blocksInGroup2 = totalCodewords % ecTotalBlocks
+ const blocksInGroup1 = ecTotalBlocks - blocksInGroup2
+
+ const totalCodewordsInGroup1 = Math.floor(totalCodewords / ecTotalBlocks)
+
+ const dataCodewordsInGroup1 = Math.floor(dataTotalCodewords / ecTotalBlocks)
+ const dataCodewordsInGroup2 = dataCodewordsInGroup1 + 1
+
+ // Number of EC codewords is the same for both groups
+ const ecCount = totalCodewordsInGroup1 - dataCodewordsInGroup1
+
+ // Initialize a Reed-Solomon encoder with a generator polynomial of degree ecCount
+ const rs = new ReedSolomonEncoder(ecCount)
+
+ let offset = 0
+ const dcData = new Array(ecTotalBlocks)
+ const ecData = new Array(ecTotalBlocks)
+ let maxDataSize = 0
+ const buffer = new Uint8Array(bitBuffer.buffer)
+
+ // Divide the buffer into the required number of blocks
+ for (let b = 0; b < ecTotalBlocks; b++) {
+ const dataSize = b < blocksInGroup1 ? dataCodewordsInGroup1 : dataCodewordsInGroup2
+
+ // extract a block of data from buffer
+ dcData[b] = buffer.slice(offset, offset + dataSize)
+
+ // Calculate EC codewords for this data block
+ ecData[b] = rs.encode(dcData[b])
+
+ offset += dataSize
+ maxDataSize = Math.max(maxDataSize, dataSize)
+ }
+
+ // Create final data
+ // Interleave the data and error correction codewords from each block
+ const data = new Uint8Array(totalCodewords)
+ let index = 0
+ let i, r
+
+ // Add data codewords
+ for (i = 0; i < maxDataSize; i++) {
+ for (r = 0; r < ecTotalBlocks; r++) {
+ if (i < dcData[r].length) {
+ data[index++] = dcData[r][i]
+ }
+ }
+ }
+
+ // Apped EC codewords
+ for (i = 0; i < ecCount; i++) {
+ for (r = 0; r < ecTotalBlocks; r++) {
+ data[index++] = ecData[r][i]
+ }
+ }
+
+ return data
+}
+
+/**
+ * Build QR Code symbol
+ *
+ * @param {String} data Input string
+ * @param {Number} version QR Code version
+ * @param {ErrorCorretionLevel} errorCorrectionLevel Error level
+ * @param {MaskPattern} maskPattern Mask pattern
+ * @return {Object} Object containing symbol data
+ */
+function createSymbol (data, version, errorCorrectionLevel, maskPattern) {
+ let segments
+
+ if (Array.isArray(data)) {
+ segments = Segments.fromArray(data)
+ } else if (typeof data === 'string') {
+ let estimatedVersion = version
+
+ if (!estimatedVersion) {
+ const rawSegments = Segments.rawSplit(data)
+
+ // Estimate best version that can contain raw splitted segments
+ estimatedVersion = Version.getBestVersionForData(rawSegments, errorCorrectionLevel)
+ }
+
+ // Build optimized segments
+ // If estimated version is undefined, try with the highest version
+ segments = Segments.fromString(data, estimatedVersion || 40)
+ } else {
+ throw new Error('Invalid data')
+ }
+
+ // Get the min version that can contain data
+ const bestVersion = Version.getBestVersionForData(segments, errorCorrectionLevel)
+
+ // If no version is found, data cannot be stored
+ if (!bestVersion) {
+ throw new Error('The amount of data is too big to be stored in a QR Code')
+ }
+
+ // If not specified, use min version as default
+ if (!version) {
+ version = bestVersion
+
+ // Check if the specified version can contain the data
+ } else if (version < bestVersion) {
+ throw new Error('\n' +
+ 'The chosen QR Code version cannot contain this amount of data.\n' +
+ 'Minimum version required to store current data is: ' + bestVersion + '.\n'
+ )
+ }
+
+ const dataBits = createData(version, errorCorrectionLevel, segments)
+
+ // Allocate matrix buffer
+ const moduleCount = Utils.getSymbolSize(version)
+ const modules = new BitMatrix(moduleCount)
+
+ // Add function modules
+ setupFinderPattern(modules, version)
+ setupTimingPattern(modules)
+ setupAlignmentPattern(modules, version)
+
+ // Add temporary dummy bits for format info just to set them as reserved.
+ // This is needed to prevent these bits from being masked by {@link MaskPattern.applyMask}
+ // since the masking operation must be performed only on the encoding region.
+ // These blocks will be replaced with correct values later in code.
+ setupFormatInfo(modules, errorCorrectionLevel, 0)
+
+ if (version >= 7) {
+ setupVersionInfo(modules, version)
+ }
+
+ // Add data codewords
+ setupData(modules, dataBits)
+
+ if (isNaN(maskPattern)) {
+ // Find best mask pattern
+ maskPattern = MaskPattern.getBestMask(modules,
+ setupFormatInfo.bind(null, modules, errorCorrectionLevel))
+ }
+
+ // Apply mask pattern
+ MaskPattern.applyMask(maskPattern, modules)
+
+ // Replace format info bits with correct values
+ setupFormatInfo(modules, errorCorrectionLevel, maskPattern)
+
+ return {
+ modules: modules,
+ version: version,
+ errorCorrectionLevel: errorCorrectionLevel,
+ maskPattern: maskPattern,
+ segments: segments
+ }
+}
+
+/**
+ * QR Code
+ *
+ * @param {String | Array} data Input data
+ * @param {Object} options Optional configurations
+ * @param {Number} options.version QR Code version
+ * @param {String} options.errorCorrectionLevel Error correction level
+ * @param {Function} options.toSJISFunc Helper func to convert utf8 to sjis
+ */
+exports.create = function create (data, options) {
+ if (typeof data === 'undefined' || data === '') {
+ throw new Error('No input text')
+ }
+
+ let errorCorrectionLevel = ECLevel.M
+ let version
+ let mask
+
+ if (typeof options !== 'undefined') {
+ // Use higher error correction level as default
+ errorCorrectionLevel = ECLevel.from(options.errorCorrectionLevel, ECLevel.M)
+ version = Version.from(options.version)
+ mask = MaskPattern.from(options.maskPattern)
+
+ if (options.toSJISFunc) {
+ Utils.setToSJISFunction(options.toSJISFunc)
+ }
+ }
+
+ return createSymbol(data, version, errorCorrectionLevel, mask)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/reed-solomon-encoder.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/reed-solomon-encoder.js
new file mode 100644
index 0000000000000000000000000000000000000000..c19842279cd54c8a09cd821aaeb36ff2c1229101
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/reed-solomon-encoder.js
@@ -0,0 +1,56 @@
+const Polynomial = require('./polynomial')
+
+function ReedSolomonEncoder (degree) {
+ this.genPoly = undefined
+ this.degree = degree
+
+ if (this.degree) this.initialize(this.degree)
+}
+
+/**
+ * Initialize the encoder.
+ * The input param should correspond to the number of error correction codewords.
+ *
+ * @param {Number} degree
+ */
+ReedSolomonEncoder.prototype.initialize = function initialize (degree) {
+ // create an irreducible generator polynomial
+ this.degree = degree
+ this.genPoly = Polynomial.generateECPolynomial(this.degree)
+}
+
+/**
+ * Encodes a chunk of data
+ *
+ * @param {Uint8Array} data Buffer containing input data
+ * @return {Uint8Array} Buffer containing encoded data
+ */
+ReedSolomonEncoder.prototype.encode = function encode (data) {
+ if (!this.genPoly) {
+ throw new Error('Encoder not initialized')
+ }
+
+ // Calculate EC for this data block
+ // extends data size to data+genPoly size
+ const paddedData = new Uint8Array(data.length + this.degree)
+ paddedData.set(data)
+
+ // The error correction codewords are the remainder after dividing the data codewords
+ // by a generator polynomial
+ const remainder = Polynomial.mod(paddedData, this.genPoly)
+
+ // return EC data blocks (last n byte, where n is the degree of genPoly)
+ // If coefficients number in remainder are less than genPoly degree,
+ // pad with 0s to the left to reach the needed number of coefficients
+ const start = this.degree - remainder.length
+ if (start > 0) {
+ const buff = new Uint8Array(this.degree)
+ buff.set(remainder, start)
+
+ return buff
+ }
+
+ return remainder
+}
+
+module.exports = ReedSolomonEncoder
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/regex.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/regex.js
new file mode 100644
index 0000000000000000000000000000000000000000..9dd13a4231a1a88d66652ac1249a316c0265c9d8
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/regex.js
@@ -0,0 +1,31 @@
+const numeric = '[0-9]+'
+const alphanumeric = '[A-Z $%*+\\-./:]+'
+let kanji = '(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|' +
+ '[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|' +
+ '[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|' +
+ '[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+'
+kanji = kanji.replace(/u/g, '\\u')
+
+const byte = '(?:(?![A-Z0-9 $%*+\\-./:]|' + kanji + ')(?:.|[\r\n]))+'
+
+exports.KANJI = new RegExp(kanji, 'g')
+exports.BYTE_KANJI = new RegExp('[^A-Z0-9 $%*+\\-./:]+', 'g')
+exports.BYTE = new RegExp(byte, 'g')
+exports.NUMERIC = new RegExp(numeric, 'g')
+exports.ALPHANUMERIC = new RegExp(alphanumeric, 'g')
+
+const TEST_KANJI = new RegExp('^' + kanji + '$')
+const TEST_NUMERIC = new RegExp('^' + numeric + '$')
+const TEST_ALPHANUMERIC = new RegExp('^[A-Z0-9 $%*+\\-./:]+$')
+
+exports.testKanji = function testKanji (str) {
+ return TEST_KANJI.test(str)
+}
+
+exports.testNumeric = function testNumeric (str) {
+ return TEST_NUMERIC.test(str)
+}
+
+exports.testAlphanumeric = function testAlphanumeric (str) {
+ return TEST_ALPHANUMERIC.test(str)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/segments.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/segments.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba8be1788cca0671a160d008e68cfa415f1e1c30
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/segments.js
@@ -0,0 +1,330 @@
+const Mode = require('./mode')
+const NumericData = require('./numeric-data')
+const AlphanumericData = require('./alphanumeric-data')
+const ByteData = require('./byte-data')
+const KanjiData = require('./kanji-data')
+const Regex = require('./regex')
+const Utils = require('./utils')
+const dijkstra = require('dijkstrajs')
+
+/**
+ * Returns UTF8 byte length
+ *
+ * @param {String} str Input string
+ * @return {Number} Number of byte
+ */
+function getStringByteLength (str) {
+ return unescape(encodeURIComponent(str)).length
+}
+
+/**
+ * Get a list of segments of the specified mode
+ * from a string
+ *
+ * @param {Mode} mode Segment mode
+ * @param {String} str String to process
+ * @return {Array} Array of object with segments data
+ */
+function getSegments (regex, mode, str) {
+ const segments = []
+ let result
+
+ while ((result = regex.exec(str)) !== null) {
+ segments.push({
+ data: result[0],
+ index: result.index,
+ mode: mode,
+ length: result[0].length
+ })
+ }
+
+ return segments
+}
+
+/**
+ * Extracts a series of segments with the appropriate
+ * modes from a string
+ *
+ * @param {String} dataStr Input string
+ * @return {Array} Array of object with segments data
+ */
+function getSegmentsFromString (dataStr) {
+ const numSegs = getSegments(Regex.NUMERIC, Mode.NUMERIC, dataStr)
+ const alphaNumSegs = getSegments(Regex.ALPHANUMERIC, Mode.ALPHANUMERIC, dataStr)
+ let byteSegs
+ let kanjiSegs
+
+ if (Utils.isKanjiModeEnabled()) {
+ byteSegs = getSegments(Regex.BYTE, Mode.BYTE, dataStr)
+ kanjiSegs = getSegments(Regex.KANJI, Mode.KANJI, dataStr)
+ } else {
+ byteSegs = getSegments(Regex.BYTE_KANJI, Mode.BYTE, dataStr)
+ kanjiSegs = []
+ }
+
+ const segs = numSegs.concat(alphaNumSegs, byteSegs, kanjiSegs)
+
+ return segs
+ .sort(function (s1, s2) {
+ return s1.index - s2.index
+ })
+ .map(function (obj) {
+ return {
+ data: obj.data,
+ mode: obj.mode,
+ length: obj.length
+ }
+ })
+}
+
+/**
+ * Returns how many bits are needed to encode a string of
+ * specified length with the specified mode
+ *
+ * @param {Number} length String length
+ * @param {Mode} mode Segment mode
+ * @return {Number} Bit length
+ */
+function getSegmentBitsLength (length, mode) {
+ switch (mode) {
+ case Mode.NUMERIC:
+ return NumericData.getBitsLength(length)
+ case Mode.ALPHANUMERIC:
+ return AlphanumericData.getBitsLength(length)
+ case Mode.KANJI:
+ return KanjiData.getBitsLength(length)
+ case Mode.BYTE:
+ return ByteData.getBitsLength(length)
+ }
+}
+
+/**
+ * Merges adjacent segments which have the same mode
+ *
+ * @param {Array} segs Array of object with segments data
+ * @return {Array} Array of object with segments data
+ */
+function mergeSegments (segs) {
+ return segs.reduce(function (acc, curr) {
+ const prevSeg = acc.length - 1 >= 0 ? acc[acc.length - 1] : null
+ if (prevSeg && prevSeg.mode === curr.mode) {
+ acc[acc.length - 1].data += curr.data
+ return acc
+ }
+
+ acc.push(curr)
+ return acc
+ }, [])
+}
+
+/**
+ * Generates a list of all possible nodes combination which
+ * will be used to build a segments graph.
+ *
+ * Nodes are divided by groups. Each group will contain a list of all the modes
+ * in which is possible to encode the given text.
+ *
+ * For example the text '12345' can be encoded as Numeric, Alphanumeric or Byte.
+ * The group for '12345' will contain then 3 objects, one for each
+ * possible encoding mode.
+ *
+ * Each node represents a possible segment.
+ *
+ * @param {Array} segs Array of object with segments data
+ * @return {Array} Array of object with segments data
+ */
+function buildNodes (segs) {
+ const nodes = []
+ for (let i = 0; i < segs.length; i++) {
+ const seg = segs[i]
+
+ switch (seg.mode) {
+ case Mode.NUMERIC:
+ nodes.push([seg,
+ { data: seg.data, mode: Mode.ALPHANUMERIC, length: seg.length },
+ { data: seg.data, mode: Mode.BYTE, length: seg.length }
+ ])
+ break
+ case Mode.ALPHANUMERIC:
+ nodes.push([seg,
+ { data: seg.data, mode: Mode.BYTE, length: seg.length }
+ ])
+ break
+ case Mode.KANJI:
+ nodes.push([seg,
+ { data: seg.data, mode: Mode.BYTE, length: getStringByteLength(seg.data) }
+ ])
+ break
+ case Mode.BYTE:
+ nodes.push([
+ { data: seg.data, mode: Mode.BYTE, length: getStringByteLength(seg.data) }
+ ])
+ }
+ }
+
+ return nodes
+}
+
+/**
+ * Builds a graph from a list of nodes.
+ * All segments in each node group will be connected with all the segments of
+ * the next group and so on.
+ *
+ * At each connection will be assigned a weight depending on the
+ * segment's byte length.
+ *
+ * @param {Array} nodes Array of object with segments data
+ * @param {Number} version QR Code version
+ * @return {Object} Graph of all possible segments
+ */
+function buildGraph (nodes, version) {
+ const table = {}
+ const graph = { start: {} }
+ let prevNodeIds = ['start']
+
+ for (let i = 0; i < nodes.length; i++) {
+ const nodeGroup = nodes[i]
+ const currentNodeIds = []
+
+ for (let j = 0; j < nodeGroup.length; j++) {
+ const node = nodeGroup[j]
+ const key = '' + i + j
+
+ currentNodeIds.push(key)
+ table[key] = { node: node, lastCount: 0 }
+ graph[key] = {}
+
+ for (let n = 0; n < prevNodeIds.length; n++) {
+ const prevNodeId = prevNodeIds[n]
+
+ if (table[prevNodeId] && table[prevNodeId].node.mode === node.mode) {
+ graph[prevNodeId][key] =
+ getSegmentBitsLength(table[prevNodeId].lastCount + node.length, node.mode) -
+ getSegmentBitsLength(table[prevNodeId].lastCount, node.mode)
+
+ table[prevNodeId].lastCount += node.length
+ } else {
+ if (table[prevNodeId]) table[prevNodeId].lastCount = node.length
+
+ graph[prevNodeId][key] = getSegmentBitsLength(node.length, node.mode) +
+ 4 + Mode.getCharCountIndicator(node.mode, version) // switch cost
+ }
+ }
+ }
+
+ prevNodeIds = currentNodeIds
+ }
+
+ for (let n = 0; n < prevNodeIds.length; n++) {
+ graph[prevNodeIds[n]].end = 0
+ }
+
+ return { map: graph, table: table }
+}
+
+/**
+ * Builds a segment from a specified data and mode.
+ * If a mode is not specified, the more suitable will be used.
+ *
+ * @param {String} data Input data
+ * @param {Mode | String} modesHint Data mode
+ * @return {Segment} Segment
+ */
+function buildSingleSegment (data, modesHint) {
+ let mode
+ const bestMode = Mode.getBestModeForData(data)
+
+ mode = Mode.from(modesHint, bestMode)
+
+ // Make sure data can be encoded
+ if (mode !== Mode.BYTE && mode.bit < bestMode.bit) {
+ throw new Error('"' + data + '"' +
+ ' cannot be encoded with mode ' + Mode.toString(mode) +
+ '.\n Suggested mode is: ' + Mode.toString(bestMode))
+ }
+
+ // Use Mode.BYTE if Kanji support is disabled
+ if (mode === Mode.KANJI && !Utils.isKanjiModeEnabled()) {
+ mode = Mode.BYTE
+ }
+
+ switch (mode) {
+ case Mode.NUMERIC:
+ return new NumericData(data)
+
+ case Mode.ALPHANUMERIC:
+ return new AlphanumericData(data)
+
+ case Mode.KANJI:
+ return new KanjiData(data)
+
+ case Mode.BYTE:
+ return new ByteData(data)
+ }
+}
+
+/**
+ * Builds a list of segments from an array.
+ * Array can contain Strings or Objects with segment's info.
+ *
+ * For each item which is a string, will be generated a segment with the given
+ * string and the more appropriate encoding mode.
+ *
+ * For each item which is an object, will be generated a segment with the given
+ * data and mode.
+ * Objects must contain at least the property "data".
+ * If property "mode" is not present, the more suitable mode will be used.
+ *
+ * @param {Array} array Array of objects with segments data
+ * @return {Array} Array of Segments
+ */
+exports.fromArray = function fromArray (array) {
+ return array.reduce(function (acc, seg) {
+ if (typeof seg === 'string') {
+ acc.push(buildSingleSegment(seg, null))
+ } else if (seg.data) {
+ acc.push(buildSingleSegment(seg.data, seg.mode))
+ }
+
+ return acc
+ }, [])
+}
+
+/**
+ * Builds an optimized sequence of segments from a string,
+ * which will produce the shortest possible bitstream.
+ *
+ * @param {String} data Input string
+ * @param {Number} version QR Code version
+ * @return {Array} Array of segments
+ */
+exports.fromString = function fromString (data, version) {
+ const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled())
+
+ const nodes = buildNodes(segs)
+ const graph = buildGraph(nodes, version)
+ const path = dijkstra.find_path(graph.map, 'start', 'end')
+
+ const optimizedSegs = []
+ for (let i = 1; i < path.length - 1; i++) {
+ optimizedSegs.push(graph.table[path[i]].node)
+ }
+
+ return exports.fromArray(mergeSegments(optimizedSegs))
+}
+
+/**
+ * Splits a string in various segments with the modes which
+ * best represent their content.
+ * The produced segments are far from being optimized.
+ * The output of this function is only used to estimate a QR Code version
+ * which may contain the data.
+ *
+ * @param {string} data Input string
+ * @return {Array} Array of segments
+ */
+exports.rawSplit = function rawSplit (data) {
+ return exports.fromArray(
+ getSegmentsFromString(data, Utils.isKanjiModeEnabled())
+ )
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/utils.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a0b87ba5ad14a058d81ebc9d9439f87f271a2e7
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/utils.js
@@ -0,0 +1,63 @@
+let toSJISFunction
+const CODEWORDS_COUNT = [
+ 0, // Not used
+ 26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
+ 404, 466, 532, 581, 655, 733, 815, 901, 991, 1085,
+ 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185,
+ 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
+]
+
+/**
+ * Returns the QR Code size for the specified version
+ *
+ * @param {Number} version QR Code version
+ * @return {Number} size of QR code
+ */
+exports.getSymbolSize = function getSymbolSize (version) {
+ if (!version) throw new Error('"version" cannot be null or undefined')
+ if (version < 1 || version > 40) throw new Error('"version" should be in range from 1 to 40')
+ return version * 4 + 17
+}
+
+/**
+ * Returns the total number of codewords used to store data and EC information.
+ *
+ * @param {Number} version QR Code version
+ * @return {Number} Data length in bits
+ */
+exports.getSymbolTotalCodewords = function getSymbolTotalCodewords (version) {
+ return CODEWORDS_COUNT[version]
+}
+
+/**
+ * Encode data with Bose-Chaudhuri-Hocquenghem
+ *
+ * @param {Number} data Value to encode
+ * @return {Number} Encoded value
+ */
+exports.getBCHDigit = function (data) {
+ let digit = 0
+
+ while (data !== 0) {
+ digit++
+ data >>>= 1
+ }
+
+ return digit
+}
+
+exports.setToSJISFunction = function setToSJISFunction (f) {
+ if (typeof f !== 'function') {
+ throw new Error('"toSJISFunc" is not a valid function.')
+ }
+
+ toSJISFunction = f
+}
+
+exports.isKanjiModeEnabled = function () {
+ return typeof toSJISFunction !== 'undefined'
+}
+
+exports.toSJIS = function toSJIS (kanji) {
+ return toSJISFunction(kanji)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version-check.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version-check.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd32b5aced810559e5ef974d483cb0660996737e
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version-check.js
@@ -0,0 +1,9 @@
+/**
+ * Check if QR Code version is valid
+ *
+ * @param {Number} version QR Code version
+ * @return {Boolean} true if valid version, false otherwise
+ */
+exports.isValid = function isValid (version) {
+ return !isNaN(version) && version >= 1 && version <= 40
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version.js
new file mode 100644
index 0000000000000000000000000000000000000000..32b846615722615db5b68f422bb46eae885246c6
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/core/version.js
@@ -0,0 +1,163 @@
+const Utils = require('./utils')
+const ECCode = require('./error-correction-code')
+const ECLevel = require('./error-correction-level')
+const Mode = require('./mode')
+const VersionCheck = require('./version-check')
+
+// Generator polynomial used to encode version information
+const G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)
+const G18_BCH = Utils.getBCHDigit(G18)
+
+function getBestVersionForDataLength (mode, length, errorCorrectionLevel) {
+ for (let currentVersion = 1; currentVersion <= 40; currentVersion++) {
+ if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, mode)) {
+ return currentVersion
+ }
+ }
+
+ return undefined
+}
+
+function getReservedBitsCount (mode, version) {
+ // Character count indicator + mode indicator bits
+ return Mode.getCharCountIndicator(mode, version) + 4
+}
+
+function getTotalBitsFromDataArray (segments, version) {
+ let totalBits = 0
+
+ segments.forEach(function (data) {
+ const reservedBits = getReservedBitsCount(data.mode, version)
+ totalBits += reservedBits + data.getBitsLength()
+ })
+
+ return totalBits
+}
+
+function getBestVersionForMixedData (segments, errorCorrectionLevel) {
+ for (let currentVersion = 1; currentVersion <= 40; currentVersion++) {
+ const length = getTotalBitsFromDataArray(segments, currentVersion)
+ if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, Mode.MIXED)) {
+ return currentVersion
+ }
+ }
+
+ return undefined
+}
+
+/**
+ * Returns version number from a value.
+ * If value is not a valid version, returns defaultValue
+ *
+ * @param {Number|String} value QR Code version
+ * @param {Number} defaultValue Fallback value
+ * @return {Number} QR Code version number
+ */
+exports.from = function from (value, defaultValue) {
+ if (VersionCheck.isValid(value)) {
+ return parseInt(value, 10)
+ }
+
+ return defaultValue
+}
+
+/**
+ * Returns how much data can be stored with the specified QR code version
+ * and error correction level
+ *
+ * @param {Number} version QR Code version (1-40)
+ * @param {Number} errorCorrectionLevel Error correction level
+ * @param {Mode} mode Data mode
+ * @return {Number} Quantity of storable data
+ */
+exports.getCapacity = function getCapacity (version, errorCorrectionLevel, mode) {
+ if (!VersionCheck.isValid(version)) {
+ throw new Error('Invalid QR Code version')
+ }
+
+ // Use Byte mode as default
+ if (typeof mode === 'undefined') mode = Mode.BYTE
+
+ // Total codewords for this QR code version (Data + Error correction)
+ const totalCodewords = Utils.getSymbolTotalCodewords(version)
+
+ // Total number of error correction codewords
+ const ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
+
+ // Total number of data codewords
+ const dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
+
+ if (mode === Mode.MIXED) return dataTotalCodewordsBits
+
+ const usableBits = dataTotalCodewordsBits - getReservedBitsCount(mode, version)
+
+ // Return max number of storable codewords
+ switch (mode) {
+ case Mode.NUMERIC:
+ return Math.floor((usableBits / 10) * 3)
+
+ case Mode.ALPHANUMERIC:
+ return Math.floor((usableBits / 11) * 2)
+
+ case Mode.KANJI:
+ return Math.floor(usableBits / 13)
+
+ case Mode.BYTE:
+ default:
+ return Math.floor(usableBits / 8)
+ }
+}
+
+/**
+ * Returns the minimum version needed to contain the amount of data
+ *
+ * @param {Segment} data Segment of data
+ * @param {Number} [errorCorrectionLevel=H] Error correction level
+ * @param {Mode} mode Data mode
+ * @return {Number} QR Code version
+ */
+exports.getBestVersionForData = function getBestVersionForData (data, errorCorrectionLevel) {
+ let seg
+
+ const ecl = ECLevel.from(errorCorrectionLevel, ECLevel.M)
+
+ if (Array.isArray(data)) {
+ if (data.length > 1) {
+ return getBestVersionForMixedData(data, ecl)
+ }
+
+ if (data.length === 0) {
+ return 1
+ }
+
+ seg = data[0]
+ } else {
+ seg = data
+ }
+
+ return getBestVersionForDataLength(seg.mode, seg.getLength(), ecl)
+}
+
+/**
+ * Returns version information with relative error correction bits
+ *
+ * The version information is included in QR Code symbols of version 7 or larger.
+ * It consists of an 18-bit sequence containing 6 data bits,
+ * with 12 error correction bits calculated using the (18, 6) Golay code.
+ *
+ * @param {Number} version QR Code version
+ * @return {Number} Encoded version info bits
+ */
+exports.getEncodedBits = function getEncodedBits (version) {
+ if (!VersionCheck.isValid(version) || version < 7) {
+ throw new Error('Invalid QR Code version')
+ }
+
+ let d = version << 12
+
+ while (Utils.getBCHDigit(d) - G18_BCH >= 0) {
+ d ^= (G18 << (Utils.getBCHDigit(d) - G18_BCH))
+ }
+
+ return (version << 12) | d
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/index.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..57c8f7036f69241990558816f2466c1a17eacd0b
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/index.js
@@ -0,0 +1,12 @@
+/*
+*copyright Ryan Day 2012
+*
+* Licensed under the MIT license:
+* http://www.opensource.org/licenses/mit-license.php
+*
+* this is the main server side application file for node-qrcode.
+* these exports use serverside canvas api methods for file IO and buffers
+*
+*/
+
+module.exports = require('./server')
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/canvas.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/canvas.js
new file mode 100644
index 0000000000000000000000000000000000000000..42050cf5214571dcb2cf589bbf9dfa80d189b94c
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/canvas.js
@@ -0,0 +1,63 @@
+const Utils = require('./utils')
+
+function clearCanvas (ctx, canvas, size) {
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
+
+ if (!canvas.style) canvas.style = {}
+ canvas.height = size
+ canvas.width = size
+ canvas.style.height = size + 'px'
+ canvas.style.width = size + 'px'
+}
+
+function getCanvasElement () {
+ try {
+ return document.createElement('canvas')
+ } catch (e) {
+ throw new Error('You need to specify a canvas element')
+ }
+}
+
+exports.render = function render (qrData, canvas, options) {
+ let opts = options
+ let canvasEl = canvas
+
+ if (typeof opts === 'undefined' && (!canvas || !canvas.getContext)) {
+ opts = canvas
+ canvas = undefined
+ }
+
+ if (!canvas) {
+ canvasEl = getCanvasElement()
+ }
+
+ opts = Utils.getOptions(opts)
+ const size = Utils.getImageWidth(qrData.modules.size, opts)
+
+ const ctx = canvasEl.getContext('2d')
+ const image = ctx.createImageData(size, size)
+ Utils.qrToImageData(image.data, qrData, opts)
+
+ clearCanvas(ctx, canvasEl, size)
+ ctx.putImageData(image, 0, 0)
+
+ return canvasEl
+}
+
+exports.renderToDataURL = function renderToDataURL (qrData, canvas, options) {
+ let opts = options
+
+ if (typeof opts === 'undefined' && (!canvas || !canvas.getContext)) {
+ opts = canvas
+ canvas = undefined
+ }
+
+ if (!opts) opts = {}
+
+ const canvasEl = exports.render(qrData, canvas, opts)
+
+ const type = opts.type || 'image/png'
+ const rendererOpts = opts.rendererOpts || {}
+
+ return canvasEl.toDataURL(type, rendererOpts.quality)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/png.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/png.js
new file mode 100644
index 0000000000000000000000000000000000000000..27421608dfb4505bb881213fc406dfd6455c316d
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/png.js
@@ -0,0 +1,78 @@
+const fs = require('fs')
+const PNG = require('pngjs').PNG
+const Utils = require('./utils')
+
+exports.render = function render (qrData, options) {
+ const opts = Utils.getOptions(options)
+ const pngOpts = opts.rendererOpts
+ const size = Utils.getImageWidth(qrData.modules.size, opts)
+
+ pngOpts.width = size
+ pngOpts.height = size
+
+ const pngImage = new PNG(pngOpts)
+ Utils.qrToImageData(pngImage.data, qrData, opts)
+
+ return pngImage
+}
+
+exports.renderToDataURL = function renderToDataURL (qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ exports.renderToBuffer(qrData, options, function (err, output) {
+ if (err) cb(err)
+ let url = 'data:image/png;base64,'
+ url += output.toString('base64')
+ cb(null, url)
+ })
+}
+
+exports.renderToBuffer = function renderToBuffer (qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ const png = exports.render(qrData, options)
+ const buffer = []
+
+ png.on('error', cb)
+
+ png.on('data', function (data) {
+ buffer.push(data)
+ })
+
+ png.on('end', function () {
+ cb(null, Buffer.concat(buffer))
+ })
+
+ png.pack()
+}
+
+exports.renderToFile = function renderToFile (path, qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ let called = false
+ const done = (...args) => {
+ if (called) return
+ called = true
+ cb.apply(null, args)
+ }
+ const stream = fs.createWriteStream(path)
+
+ stream.on('error', done)
+ stream.on('close', done)
+
+ exports.renderToFileStream(stream, qrData, options)
+}
+
+exports.renderToFileStream = function renderToFileStream (stream, qrData, options) {
+ const png = exports.render(qrData, options)
+ png.pack().pipe(stream)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg-tag.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg-tag.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0839fe06985b3a2f93966e650157a83e0ce5892
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg-tag.js
@@ -0,0 +1,81 @@
+const Utils = require('./utils')
+
+function getColorAttrib (color, attrib) {
+ const alpha = color.a / 255
+ const str = attrib + '="' + color.hex + '"'
+
+ return alpha < 1
+ ? str + ' ' + attrib + '-opacity="' + alpha.toFixed(2).slice(1) + '"'
+ : str
+}
+
+function svgCmd (cmd, x, y) {
+ let str = cmd + x
+ if (typeof y !== 'undefined') str += ' ' + y
+
+ return str
+}
+
+function qrToPath (data, size, margin) {
+ let path = ''
+ let moveBy = 0
+ let newRow = false
+ let lineLength = 0
+
+ for (let i = 0; i < data.length; i++) {
+ const col = Math.floor(i % size)
+ const row = Math.floor(i / size)
+
+ if (!col && !newRow) newRow = true
+
+ if (data[i]) {
+ lineLength++
+
+ if (!(i > 0 && col > 0 && data[i - 1])) {
+ path += newRow
+ ? svgCmd('M', col + margin, 0.5 + row + margin)
+ : svgCmd('m', moveBy, 0)
+
+ moveBy = 0
+ newRow = false
+ }
+
+ if (!(col + 1 < size && data[i + 1])) {
+ path += svgCmd('h', lineLength)
+ lineLength = 0
+ }
+ } else {
+ moveBy++
+ }
+ }
+
+ return path
+}
+
+exports.render = function render (qrData, options, cb) {
+ const opts = Utils.getOptions(options)
+ const size = qrData.modules.size
+ const data = qrData.modules.data
+ const qrcodesize = size + opts.margin * 2
+
+ const bg = !opts.color.light.a
+ ? ''
+ : ''
+
+ const path =
+ ''
+
+ const viewBox = 'viewBox="' + '0 0 ' + qrcodesize + ' ' + qrcodesize + '"'
+
+ const width = !opts.width ? '' : 'width="' + opts.width + '" height="' + opts.width + '" '
+
+ const svgTag = '\n'
+
+ if (typeof cb === 'function') {
+ cb(null, svgTag)
+ }
+
+ return svgTag
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba99d14cd162a5fbe4b361a84aecfb6faf0e81a3
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/svg.js
@@ -0,0 +1,19 @@
+const svgTagRenderer = require('./svg-tag')
+
+exports.render = svgTagRenderer.render
+
+exports.renderToFile = function renderToFile (path, qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ const fs = require('fs')
+ const svgTag = exports.render(qrData, options)
+
+ const xmlStr = '' +
+ '' +
+ svgTag
+
+ fs.writeFile(path, xmlStr, cb)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal.js
new file mode 100644
index 0000000000000000000000000000000000000000..36ddfde78c3a66029d56b367fe612aafd17ab459
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal.js
@@ -0,0 +1,9 @@
+const big = require('./terminal/terminal')
+const small = require('./terminal/terminal-small')
+
+exports.render = function (qrData, options, cb) {
+ if (options && options.small) {
+ return small.render(qrData, options, cb)
+ }
+ return big.render(qrData, options, cb)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal-small.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal-small.js
new file mode 100644
index 0000000000000000000000000000000000000000..9810d4e1510f3ce52afcf85a740dd133511cbde3
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal-small.js
@@ -0,0 +1,85 @@
+const backgroundWhite = '\x1b[47m'
+const backgroundBlack = '\x1b[40m'
+const foregroundWhite = '\x1b[37m'
+const foregroundBlack = '\x1b[30m'
+const reset = '\x1b[0m'
+const lineSetupNormal = backgroundWhite + foregroundBlack // setup colors
+const lineSetupInverse = backgroundBlack + foregroundWhite // setup colors
+
+const createPalette = function (lineSetup, foregroundWhite, foregroundBlack) {
+ return {
+ // 1 ... white, 2 ... black, 0 ... transparent (default)
+
+ '00': reset + ' ' + lineSetup,
+ '01': reset + foregroundWhite + '▄' + lineSetup,
+ '02': reset + foregroundBlack + '▄' + lineSetup,
+ 10: reset + foregroundWhite + '▀' + lineSetup,
+ 11: ' ',
+ 12: '▄',
+ 20: reset + foregroundBlack + '▀' + lineSetup,
+ 21: '▀',
+ 22: '█'
+ }
+}
+
+/**
+ * Returns code for QR pixel
+ * @param {boolean[][]} modules
+ * @param {number} size
+ * @param {number} x
+ * @param {number} y
+ * @return {'0' | '1' | '2'}
+ */
+const mkCodePixel = function (modules, size, x, y) {
+ const sizePlus = size + 1
+ if ((x >= sizePlus) || (y >= sizePlus) || (y < -1) || (x < -1)) return '0'
+ if ((x >= size) || (y >= size) || (y < 0) || (x < 0)) return '1'
+ const idx = (y * size) + x
+ return modules[idx] ? '2' : '1'
+}
+
+/**
+ * Returns code for four QR pixels. Suitable as key in palette.
+ * @param {boolean[][]} modules
+ * @param {number} size
+ * @param {number} x
+ * @param {number} y
+ * @return {keyof palette}
+ */
+const mkCode = function (modules, size, x, y) {
+ return (
+ mkCodePixel(modules, size, x, y) +
+ mkCodePixel(modules, size, x, y + 1)
+ )
+}
+
+exports.render = function (qrData, options, cb) {
+ const size = qrData.modules.size
+ const data = qrData.modules.data
+
+ const inverse = !!(options && options.inverse)
+ const lineSetup = options && options.inverse ? lineSetupInverse : lineSetupNormal
+ const white = inverse ? foregroundBlack : foregroundWhite
+ const black = inverse ? foregroundWhite : foregroundBlack
+
+ const palette = createPalette(lineSetup, white, black)
+ const newLine = reset + '\n' + lineSetup
+
+ let output = lineSetup // setup colors
+
+ for (let y = -1; y < size + 1; y += 2) {
+ for (let x = -1; x < size; x++) {
+ output += palette[mkCode(data, size, x, y)]
+ }
+
+ output += palette[mkCode(data, size, size, y)] + newLine
+ }
+
+ output += reset
+
+ if (typeof cb === 'function') {
+ cb(null, output)
+ }
+
+ return output
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal.js
new file mode 100644
index 0000000000000000000000000000000000000000..f15610b5510b649c96497548a20104220e17da19
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/terminal/terminal.js
@@ -0,0 +1,49 @@
+// let Utils = require('./utils')
+
+exports.render = function (qrData, options, cb) {
+ const size = qrData.modules.size
+ const data = qrData.modules.data
+
+ // let opts = Utils.getOptions(options)
+
+ // use same scheme as https://github.com/gtanner/qrcode-terminal because it actually works! =)
+ const black = '\x1b[40m \x1b[0m'
+ const white = '\x1b[47m \x1b[0m'
+
+ let output = ''
+ const hMargin = Array(size + 3).join(white)
+ const vMargin = Array(2).join(white)
+
+ output += hMargin + '\n'
+ for (let i = 0; i < size; ++i) {
+ output += white
+ for (let j = 0; j < size; j++) {
+ // let topModule = data[i * size + j]
+ // let bottomModule = data[(i + 1) * size + j]
+
+ output += data[i * size + j] ? black : white// getBlockChar(topModule, bottomModule)
+ }
+ // output += white+'\n'
+ output += vMargin + '\n'
+ }
+
+ output += hMargin + '\n'
+
+ if (typeof cb === 'function') {
+ cb(null, output)
+ }
+
+ return output
+}
+/*
+exports.renderToFile = function renderToFile (path, qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ let fs = require('fs')
+ let utf8 = exports.render(qrData, options)
+ fs.writeFile(path, utf8, cb)
+}
+*/
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utf8.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utf8.js
new file mode 100644
index 0000000000000000000000000000000000000000..d76116e58d1b54ba88a9479ff813a71f7557fbee
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utf8.js
@@ -0,0 +1,71 @@
+const Utils = require('./utils')
+
+const BLOCK_CHAR = {
+ WW: ' ',
+ WB: '▄',
+ BB: '█',
+ BW: '▀'
+}
+
+const INVERTED_BLOCK_CHAR = {
+ BB: ' ',
+ BW: '▄',
+ WW: '█',
+ WB: '▀'
+}
+
+function getBlockChar (top, bottom, blocks) {
+ if (top && bottom) return blocks.BB
+ if (top && !bottom) return blocks.BW
+ if (!top && bottom) return blocks.WB
+ return blocks.WW
+}
+
+exports.render = function (qrData, options, cb) {
+ const opts = Utils.getOptions(options)
+ let blocks = BLOCK_CHAR
+ if (opts.color.dark.hex === '#ffffff' || opts.color.light.hex === '#000000') {
+ blocks = INVERTED_BLOCK_CHAR
+ }
+
+ const size = qrData.modules.size
+ const data = qrData.modules.data
+
+ let output = ''
+ let hMargin = Array(size + (opts.margin * 2) + 1).join(blocks.WW)
+ hMargin = Array((opts.margin / 2) + 1).join(hMargin + '\n')
+
+ const vMargin = Array(opts.margin + 1).join(blocks.WW)
+
+ output += hMargin
+ for (let i = 0; i < size; i += 2) {
+ output += vMargin
+ for (let j = 0; j < size; j++) {
+ const topModule = data[i * size + j]
+ const bottomModule = data[(i + 1) * size + j]
+
+ output += getBlockChar(topModule, bottomModule, blocks)
+ }
+
+ output += vMargin + '\n'
+ }
+
+ output += hMargin.slice(0, -1)
+
+ if (typeof cb === 'function') {
+ cb(null, output)
+ }
+
+ return output
+}
+
+exports.renderToFile = function renderToFile (path, qrData, options, cb) {
+ if (typeof cb === 'undefined') {
+ cb = options
+ options = undefined
+ }
+
+ const fs = require('fs')
+ const utf8 = exports.render(qrData, options)
+ fs.writeFile(path, utf8, cb)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utils.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..87239dc517462881abb3597bcaa3d25cde2ab56f
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/renderer/utils.js
@@ -0,0 +1,99 @@
+function hex2rgba (hex) {
+ if (typeof hex === 'number') {
+ hex = hex.toString()
+ }
+
+ if (typeof hex !== 'string') {
+ throw new Error('Color should be defined as hex string')
+ }
+
+ let hexCode = hex.slice().replace('#', '').split('')
+ if (hexCode.length < 3 || hexCode.length === 5 || hexCode.length > 8) {
+ throw new Error('Invalid hex color: ' + hex)
+ }
+
+ // Convert from short to long form (fff -> ffffff)
+ if (hexCode.length === 3 || hexCode.length === 4) {
+ hexCode = Array.prototype.concat.apply([], hexCode.map(function (c) {
+ return [c, c]
+ }))
+ }
+
+ // Add default alpha value
+ if (hexCode.length === 6) hexCode.push('F', 'F')
+
+ const hexValue = parseInt(hexCode.join(''), 16)
+
+ return {
+ r: (hexValue >> 24) & 255,
+ g: (hexValue >> 16) & 255,
+ b: (hexValue >> 8) & 255,
+ a: hexValue & 255,
+ hex: '#' + hexCode.slice(0, 6).join('')
+ }
+}
+
+exports.getOptions = function getOptions (options) {
+ if (!options) options = {}
+ if (!options.color) options.color = {}
+
+ const margin = typeof options.margin === 'undefined' ||
+ options.margin === null ||
+ options.margin < 0
+ ? 4
+ : options.margin
+
+ const width = options.width && options.width >= 21 ? options.width : undefined
+ const scale = options.scale || 4
+
+ return {
+ width: width,
+ scale: width ? 4 : scale,
+ margin: margin,
+ color: {
+ dark: hex2rgba(options.color.dark || '#000000ff'),
+ light: hex2rgba(options.color.light || '#ffffffff')
+ },
+ type: options.type,
+ rendererOpts: options.rendererOpts || {}
+ }
+}
+
+exports.getScale = function getScale (qrSize, opts) {
+ return opts.width && opts.width >= qrSize + opts.margin * 2
+ ? opts.width / (qrSize + opts.margin * 2)
+ : opts.scale
+}
+
+exports.getImageWidth = function getImageWidth (qrSize, opts) {
+ const scale = exports.getScale(qrSize, opts)
+ return Math.floor((qrSize + opts.margin * 2) * scale)
+}
+
+exports.qrToImageData = function qrToImageData (imgData, qr, opts) {
+ const size = qr.modules.size
+ const data = qr.modules.data
+ const scale = exports.getScale(size, opts)
+ const symbolSize = Math.floor((size + opts.margin * 2) * scale)
+ const scaledMargin = opts.margin * scale
+ const palette = [opts.color.light, opts.color.dark]
+
+ for (let i = 0; i < symbolSize; i++) {
+ for (let j = 0; j < symbolSize; j++) {
+ let posDst = (i * symbolSize + j) * 4
+ let pxColor = opts.color.light
+
+ if (i >= scaledMargin && j >= scaledMargin &&
+ i < symbolSize - scaledMargin && j < symbolSize - scaledMargin) {
+ const iSrc = Math.floor((i - scaledMargin) / scale)
+ const jSrc = Math.floor((j - scaledMargin) / scale)
+ pxColor = palette[data[iSrc * size + jSrc] ? 1 : 0]
+ }
+
+ imgData[posDst++] = pxColor.r
+ imgData[posDst++] = pxColor.g
+ imgData[posDst++] = pxColor.b
+ imgData[posDst] = pxColor.a
+ }
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/server.js b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/server.js
new file mode 100644
index 0000000000000000000000000000000000000000..619e398ed653c91ff39ff708180d531344924c97
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/lib/server.js
@@ -0,0 +1,138 @@
+const canPromise = require('./can-promise')
+const QRCode = require('./core/qrcode')
+const PngRenderer = require('./renderer/png')
+const Utf8Renderer = require('./renderer/utf8')
+const TerminalRenderer = require('./renderer/terminal')
+const SvgRenderer = require('./renderer/svg')
+
+function checkParams (text, opts, cb) {
+ if (typeof text === 'undefined') {
+ throw new Error('String required as first argument')
+ }
+
+ if (typeof cb === 'undefined') {
+ cb = opts
+ opts = {}
+ }
+
+ if (typeof cb !== 'function') {
+ if (!canPromise()) {
+ throw new Error('Callback required as last argument')
+ } else {
+ opts = cb || {}
+ cb = null
+ }
+ }
+
+ return {
+ opts: opts,
+ cb: cb
+ }
+}
+
+function getTypeFromFilename (path) {
+ return path.slice((path.lastIndexOf('.') - 1 >>> 0) + 2).toLowerCase()
+}
+
+function getRendererFromType (type) {
+ switch (type) {
+ case 'svg':
+ return SvgRenderer
+
+ case 'txt':
+ case 'utf8':
+ return Utf8Renderer
+
+ case 'png':
+ case 'image/png':
+ default:
+ return PngRenderer
+ }
+}
+
+function getStringRendererFromType (type) {
+ switch (type) {
+ case 'svg':
+ return SvgRenderer
+
+ case 'terminal':
+ return TerminalRenderer
+
+ case 'utf8':
+ default:
+ return Utf8Renderer
+ }
+}
+
+function render (renderFunc, text, params) {
+ if (!params.cb) {
+ return new Promise(function (resolve, reject) {
+ try {
+ const data = QRCode.create(text, params.opts)
+ return renderFunc(data, params.opts, function (err, data) {
+ return err ? reject(err) : resolve(data)
+ })
+ } catch (e) {
+ reject(e)
+ }
+ })
+ }
+
+ try {
+ const data = QRCode.create(text, params.opts)
+ return renderFunc(data, params.opts, params.cb)
+ } catch (e) {
+ params.cb(e)
+ }
+}
+
+exports.create = QRCode.create
+
+exports.toCanvas = require('./browser').toCanvas
+
+exports.toString = function toString (text, opts, cb) {
+ const params = checkParams(text, opts, cb)
+ const type = params.opts ? params.opts.type : undefined
+ const renderer = getStringRendererFromType(type)
+ return render(renderer.render, text, params)
+}
+
+exports.toDataURL = function toDataURL (text, opts, cb) {
+ const params = checkParams(text, opts, cb)
+ const renderer = getRendererFromType(params.opts.type)
+ return render(renderer.renderToDataURL, text, params)
+}
+
+exports.toBuffer = function toBuffer (text, opts, cb) {
+ const params = checkParams(text, opts, cb)
+ const renderer = getRendererFromType(params.opts.type)
+ return render(renderer.renderToBuffer, text, params)
+}
+
+exports.toFile = function toFile (path, text, opts, cb) {
+ if (typeof path !== 'string' || !(typeof text === 'string' || typeof text === 'object')) {
+ throw new Error('Invalid argument')
+ }
+
+ if ((arguments.length < 3) && !canPromise()) {
+ throw new Error('Too few arguments provided')
+ }
+
+ const params = checkParams(text, opts, cb)
+ const type = params.opts.type || getTypeFromFilename(path)
+ const renderer = getRendererFromType(type)
+ const renderToFile = renderer.renderToFile.bind(null, path)
+
+ return render(renderToFile, text, params)
+}
+
+exports.toFileStream = function toFileStream (stream, text, opts) {
+ if (arguments.length < 2) {
+ throw new Error('Too few arguments provided')
+ }
+
+ const params = checkParams(text, opts, stream.emit.bind(stream, 'error'))
+ const renderer = getRendererFromType('png') // Only png support for now
+ const renderToFileStream = renderer.renderToFileStream.bind(null, stream)
+ render(renderToFileStream, text, params)
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/license b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/license
new file mode 100644
index 0000000000000000000000000000000000000000..4e2b3b93334b6d872ff336f8b680e1bc59f2a4ff
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/license
@@ -0,0 +1,10 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Ryan Day
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode
new file mode 100644
index 0000000000000000000000000000000000000000..518ce8b6e19c5053ee1acc4ba07a5843151653d8
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode
@@ -0,0 +1,17 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -z "$NODE_PATH" ]; then
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+else
+ export NODE_PATH="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules:$NODE_PATH"
+fi
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../../bin/qrcode" "$@"
+else
+ exec node "$basedir/../../bin/qrcode" "$@"
+fi
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.CMD b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.CMD
new file mode 100644
index 0000000000000000000000000000000000000000..b01cd9ac5988607289f9950cafd24e44bb5f7589
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.CMD
@@ -0,0 +1,12 @@
+@SETLOCAL
+@IF NOT DEFINED NODE_PATH (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+) ELSE (
+ @SET "NODE_PATH=E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules;%NODE_PATH%"
+)
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\..\bin\qrcode" %*
+) ELSE (
+ @SET PATHEXT=%PATHEXT:;.JS;=;%
+ node "%~dp0\..\..\bin\qrcode" %*
+)
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.ps1 b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..62172602ab989feb93e1eaa1c6a74d9e19fb8cac
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/node_modules/.bin/qrcode.ps1
@@ -0,0 +1,41 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+$pathsep=":"
+$env_node_path=$env:NODE_PATH
+$new_node_path="E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\bin\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules\qrcode\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\qrcode@1.5.3\node_modules;E:\bot\yunzai\Yunzai\node_modules\.pnpm\node_modules"
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+ $pathsep=";"
+} else {
+ $new_node_path="/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/bin/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules/qrcode/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/qrcode@1.5.3/node_modules:/mnt/e/bot/yunzai/Yunzai/node_modules/.pnpm/node_modules"
+}
+if ([string]::IsNullOrEmpty($env_node_path)) {
+ $env:NODE_PATH=$new_node_path
+} else {
+ $env:NODE_PATH="$new_node_path$pathsep$env_node_path"
+}
+
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../../bin/qrcode" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../../bin/qrcode" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../../bin/qrcode" $args
+ } else {
+ & "node$exe" "$basedir/../../bin/qrcode" $args
+ }
+ $ret=$LASTEXITCODE
+}
+$env:NODE_PATH=$env_node_path
+exit $ret
diff --git a/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/package.json b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e59eb915fd2c24688d05f941b0f5fa93f4cb2fd2
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/node_modules/qrcode/package.json
@@ -0,0 +1,78 @@
+{
+ "name": "qrcode",
+ "description": "QRCode / 2d Barcode api with both server side and client side support using canvas",
+ "version": "1.5.3",
+ "author": "Ryan Day ",
+ "contributors": [
+ "Vincenzo Greco ",
+ "Linus Unnebäck "
+ ],
+ "keywords": [
+ "qr",
+ "code",
+ "canvas",
+ "qrcode"
+ ],
+ "main": "./lib/index.js",
+ "browser": {
+ "./lib/index.js": "./lib/browser.js",
+ "fs": false
+ },
+ "files": [
+ "bin",
+ "build",
+ "lib",
+ "helper"
+ ],
+ "homepage": "http://github.com/soldair/node-qrcode",
+ "license": "MIT",
+ "scripts": {
+ "lint": "standard",
+ "pretest": "npm run lint",
+ "test": "node --throw-deprecation test.js",
+ "build": "rollup -c",
+ "prepublish": "npm run build",
+ "browser": "node examples/clientsideserver.js"
+ },
+ "bin": {
+ "qrcode": "./bin/qrcode"
+ },
+ "dependencies": {
+ "dijkstrajs": "^1.0.1",
+ "encode-utf8": "^1.0.3",
+ "pngjs": "^5.0.0",
+ "yargs": "^15.3.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.9.0",
+ "@babel/preset-env": "^7.9.5",
+ "@rollup/plugin-commonjs": "^11.1.0",
+ "@rollup/plugin-node-resolve": "^7.1.3",
+ "browserify": "^16.5.1",
+ "canvas": "^2.8.0",
+ "canvasutil": "0.0.4",
+ "colors": "^1.4.0",
+ "express": "^4.17.1",
+ "htmlparser2": "^4.1.0",
+ "rollup": "^2.6.1",
+ "rollup-plugin-babel": "^4.4.0",
+ "rollup-plugin-terser": "^5.3.0",
+ "sinon": "^9.0.2",
+ "standard": "^16.0.4",
+ "tap": "^16.2.0"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/soldair/node-qrcode.git"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "standard": {
+ "ignore": [
+ "build/",
+ "examples/vendors/",
+ "lib/core/regex.js"
+ ]
+ }
+}
diff --git a/Yunzai/plugins/TRSS-Plugin/package.json b/Yunzai/plugins/TRSS-Plugin/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8a2f225b8b1f5ede1b93ba6a828303ef0a768fbf
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "TRSS-Plugin",
+ "type": "module",
+ "author": "TimeRainStarSky",
+ "dependencies": {
+ "ansi_up": "^6.0.2",
+ "markdown-it": "^13.0.1",
+ "qrcode": "^1.5.3"
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/TRSS-Plugin/poetry.lock b/Yunzai/plugins/TRSS-Plugin/poetry.lock
new file mode 100644
index 0000000000000000000000000000000000000000..0b08332f3c8a6545f098c7539f6e1aac24e023e4
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/poetry.lock
@@ -0,0 +1,4045 @@
+# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
+
+[[package]]
+name = "absl-py"
+version = "1.4.0"
+description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d"},
+ {file = "absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "addict"
+version = "2.4.0"
+description = "Addict is a dictionary whose items can be set using both attribute and item syntax."
+optional = false
+python-versions = "*"
+files = [
+ {file = "addict-2.4.0-py3-none-any.whl", hash = "sha256:249bb56bbfd3cdc2a004ea0ff4c2b6ddc84d53bc2194761636eb314d5cfa5dfc"},
+ {file = "addict-2.4.0.tar.gz", hash = "sha256:b3b2210e0e067a281f5646c8c5db92e99b7231ea8b0eb5f74dbdf9e259d4e494"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "attrs"
+version = "23.1.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
+ {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "audioread"
+version = "3.0.0"
+description = "multi-library, cross-platform audio decoding"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "audioread-3.0.0.tar.gz", hash = "sha256:121995bd207eb1fda3d566beb851d3534275925bc35a4fb6da0cb11de0f7251a"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "babel"
+version = "2.12.1"
+description = "Internationalization utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"},
+ {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "basicsr"
+version = "1.4.2"
+description = "Open Source Image and Video Super-Resolution Toolbox"
+optional = false
+python-versions = "*"
+files = [
+ {file = "basicsr-1.4.2.tar.gz", hash = "sha256:b89b595a87ef964cda9913b4d99380ddb6554c965577c0c10cb7b78e31301e87"},
+]
+
+[package.dependencies]
+addict = "*"
+future = "*"
+lmdb = "*"
+numpy = ">=1.17"
+opencv-python = "*"
+Pillow = "*"
+pyyaml = "*"
+requests = "*"
+scikit-image = "*"
+scipy = "*"
+tb-nightly = "*"
+torch = ">=1.7"
+torchvision = "*"
+tqdm = "*"
+yapf = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "blinker"
+version = "1.6.2"
+description = "Fast, simple object-to-object and broadcast signaling"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "blinker-1.6.2-py3-none-any.whl", hash = "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0"},
+ {file = "blinker-1.6.2.tar.gz", hash = "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cachetools"
+version = "5.3.1"
+description = "Extensible memoizing collections and decorators"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"},
+ {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "certifi"
+version = "2023.7.22"
+description = "Python package for providing Mozilla's CA Bundle."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
+ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cffi"
+version = "1.15.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = "*"
+files = [
+ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
+ {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
+ {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
+ {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
+ {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
+ {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
+ {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
+ {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
+ {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
+ {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
+ {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
+ {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
+ {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
+ {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
+ {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
+ {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
+ {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
+ {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
+ {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "charset-normalizer"
+version = "3.2.0"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
+ {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "clldutils"
+version = "3.19.0"
+description = "Utilities for programmatic data curation"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "clldutils-3.19.0-py2.py3-none-any.whl", hash = "sha256:09a6b26f7969c077fcc0133d6f0e08774612648511368d2ff503b5fbeb9227a9"},
+ {file = "clldutils-3.19.0.tar.gz", hash = "sha256:2406491ae40e971f46ee1a7205d57ac9c36e923bc89cd4bd4b6e9c3d2460a955"},
+]
+
+[package.dependencies]
+attrs = ">=18.1.0"
+colorlog = "*"
+lxml = "*"
+markdown = "*"
+markupsafe = "*"
+pylatexenc = "*"
+python-dateutil = "*"
+tabulate = ">=0.7.7"
+
+[package.extras]
+dev = ["build", "flake8", "twine", "wheel"]
+doc = ["sphinx", "sphinx-autodoc-typehints", "sphinx-rtd-theme"]
+test = ["pytest (>=5)", "pytest-cov", "pytest-mock", "tox"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cmake"
+version = "3.27.2"
+description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software"
+optional = false
+python-versions = "*"
+files = [
+ {file = "cmake-3.27.2-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:96ac856c4d6b2104408848f0005a8ab2229d4135b171ea9a03e8c33039ede420"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:11fe6129d07982721c5965fd804a4056b8c6e9c4f482ac9e0fe41bb3abc1ab5f"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:f0c64e89e2ea59592980c4fe3821d712fee0e74cf87c2aaec5b3ab9aa809a57c"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ca7650477dff2a1138776b28b79c0e99127be733d3978922e8f87b56a433eed6"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ab2e40fe09e76a7ef67da2bbbf7a4cd1f52db4f1c7b6ccdda2539f918830343a"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:980ee19f12c808cb8ddb56fdcee832501a9f9631799d8b4fc625c0a0b5fb4c55"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:115d30ca0760e3861d9ad6b3288cd11ee72a785b81227da0c1765d3b84e2c009"},
+ {file = "cmake-3.27.2-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efc338c939d6d435890a52458a260bf0942bd8392b648d7532a72c1ec0764e18"},
+ {file = "cmake-3.27.2-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:7f7438c60ccc01765b67abfb1797787c3b9459d500a804ed70a4cc181bc02204"},
+ {file = "cmake-3.27.2-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:294f008734267e0eee1574ad1b911bed137bc907ab19d60a618dab4615aa1fca"},
+ {file = "cmake-3.27.2-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:197a34dc62ee149ced343545fac67e5a30b93fda65250b065726f86ce92bdada"},
+ {file = "cmake-3.27.2-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:afb46ad883b174fb64347802ba5878423551dbd5847bb64669c39a5957c06eb7"},
+ {file = "cmake-3.27.2-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:83611ffd155e270a6b13bbf0cfd4e8688ebda634f448aa2e3734006c745bf33f"},
+ {file = "cmake-3.27.2-py2.py3-none-win32.whl", hash = "sha256:53e12deb893da935e236f93accd47dbe2806620cd7654986234dc4487cc49652"},
+ {file = "cmake-3.27.2-py2.py3-none-win_amd64.whl", hash = "sha256:611f9722c68c40352d38a6c01960ab038c3d0419e7aee3bf18f95b23031e0dfe"},
+ {file = "cmake-3.27.2-py2.py3-none-win_arm64.whl", hash = "sha256:30620326b51ac2ce0d8f476747af6367a7ea21075c4d065fad9443904b07476a"},
+ {file = "cmake-3.27.2.tar.gz", hash = "sha256:7cd6e2d7d5a1125f8c26c4f65214f8c942e3f276f98c16cb62ae382c35609f25"},
+]
+
+[package.extras]
+test = ["coverage (>=4.2)", "flake8 (>=3.0.4)", "path.py (>=11.5.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.4.0)", "pytest-runner (>=2.9)", "pytest-virtualenv (>=1.7.0)", "scikit-build (>=0.10.0)", "setuptools (>=28.0.0)", "virtualenv (>=15.0.3)", "wheel"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cn2an"
+version = "0.5.22"
+description = "Convert Chinese numerals and Arabic numerals."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "cn2an-0.5.22-py3-none-any.whl", hash = "sha256:cba4c8f305b43da01f50696047cca3116c727424ac62338da6a3426e01454f3e"},
+ {file = "cn2an-0.5.22.tar.gz", hash = "sha256:27ae5b56441d7329ed2ececffa026bfa8fc353dcf1fb0d9146b303b9cce3ac37"},
+]
+
+[package.dependencies]
+proces = ">=0.1.3"
+setuptools = ">=47.3.1"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "coloredlogs"
+version = "15.0.1"
+description = "Colored terminal output for Python's logging module"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
+ {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
+]
+
+[package.dependencies]
+humanfriendly = ">=9.1"
+
+[package.extras]
+cron = ["capturer (>=2.4)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "colorlog"
+version = "6.7.0"
+description = "Add colours to the output of Python's logging module."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "colorlog-6.7.0-py2.py3-none-any.whl", hash = "sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662"},
+ {file = "colorlog-6.7.0.tar.gz", hash = "sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+
+[package.extras]
+development = ["black", "flake8", "mypy", "pytest", "types-colorama"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "contourpy"
+version = "1.1.0"
+description = "Python library for calculating contours of 2D quadrilateral grids"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"},
+ {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"},
+ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"},
+ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"},
+ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"},
+ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"},
+ {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"},
+ {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"},
+ {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"},
+ {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"},
+ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"},
+ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"},
+ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"},
+ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"},
+ {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"},
+ {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"},
+ {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"},
+ {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"},
+ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"},
+ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"},
+ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"},
+ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"},
+ {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"},
+ {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"},
+ {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"},
+ {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"},
+ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"},
+ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"},
+ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"},
+ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"},
+ {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"},
+ {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"},
+ {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"},
+ {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"},
+ {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"},
+ {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"},
+ {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"},
+ {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"},
+ {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"},
+]
+
+[package.dependencies]
+numpy = ">=1.16"
+
+[package.extras]
+bokeh = ["bokeh", "selenium"]
+docs = ["furo", "sphinx-copybutton"]
+mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"]
+test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
+test-no-images = ["pytest", "pytest-cov", "wurlitzer"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "csvw"
+version = "3.1.3"
+description = "Python library to work with CSVW described tabular data"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "csvw-3.1.3-py2.py3-none-any.whl", hash = "sha256:0ced874b139ab5bbb2d1ce7070386dc2623c4953dc3c0f984c01987107fb8955"},
+ {file = "csvw-3.1.3.tar.gz", hash = "sha256:c51a412cd8a3d39a6f35e25e941bab8fab141d9e53ef49156678ec1dc92802f6"},
+]
+
+[package.dependencies]
+attrs = ">=18.1"
+babel = "*"
+colorama = "*"
+isodate = "*"
+jsonschema = "*"
+language-tags = "*"
+python-dateutil = "*"
+rdflib = "*"
+requests = "*"
+rfc3986 = "<2"
+uritemplate = ">=3.0.0"
+
+[package.extras]
+dev = ["build", "flake8", "twine", "wheel"]
+docs = ["sphinx", "sphinx-autodoc-typehints", "sphinx-rtd-theme"]
+test = ["frictionless", "pytest (>=5)", "pytest-cov", "pytest-mock", "requests-mock"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cycler"
+version = "0.11.0"
+description = "Composable style cycles"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"},
+ {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "cython"
+version = "3.0.0"
+description = "The Cython compiler for writing C extensions in the Python language."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "Cython-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c7d728e1a49ad01d41181e3a9ea80b8d14e825f4679e4dd837cbf7bca7998a5"},
+ {file = "Cython-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:626a4a6ef4b7ced87c348ea805488e4bd39dad9d0b39659aa9e1040b62bbfedf"},
+ {file = "Cython-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c900d1ca9f622b969ac7d8fc44bdae140a4a6c7d8819413b51f3ccd0586a09"},
+ {file = "Cython-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a65bc50dc1bc2faeafd9425defbdef6a468974f5c4192497ff7f14adccfdcd32"},
+ {file = "Cython-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b71b399b10b038b056ad12dce1e317a8aa7a96e99de7e4fa2fa5d1c9415cfb9"},
+ {file = "Cython-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f42f304c097cc53e9eb5f1a1d150380353d5018a3191f1b77f0de353c762181e"},
+ {file = "Cython-3.0.0-cp310-cp310-win32.whl", hash = "sha256:3e234e2549e808d9259fdb23ebcfd145be30c638c65118326ec33a8d29248dc2"},
+ {file = "Cython-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:829c8333195100448a23863cf64a07e1334fae6a275aefe871458937911531b6"},
+ {file = "Cython-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06db81b1a01858fcc406616f8528e686ffb6cf7c3d78fb83767832bfecea8ad8"},
+ {file = "Cython-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c93634845238645ce7abf63a56b1c5b6248189005c7caff898fd4a0dac1c5e1e"},
+ {file = "Cython-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa606675c6bd23478b1d174e2a84e3c5a2c660968f97dc455afe0fae198f9d3d"},
+ {file = "Cython-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3355e6f690184f984eeb108b0f5bbc4bcf8b9444f8168933acf79603abf7baf"},
+ {file = "Cython-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93a34e1ca8afa4b7075b02ed14a7e4969256297029fb1bfd4cbe48f7290dbcff"},
+ {file = "Cython-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb1165ca9e78823f9ad1efa5b3d83156f868eabd679a615d140a3021bb92cd65"},
+ {file = "Cython-3.0.0-cp311-cp311-win32.whl", hash = "sha256:2fadde1da055944f5e1e17625055f54ddd11f451889110278ef30e07bd5e1695"},
+ {file = "Cython-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:254ed1f03a6c237fa64f0c6e44862058de65bfa2e6a3b48ca3c205492e0653aa"},
+ {file = "Cython-3.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e212237b7531759befb92699c452cd65074a78051ae4ee36ff8b237395ecf3d"},
+ {file = "Cython-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f29307463eba53747b31f71394ed087e3e3e264dcc433e62de1d51f5c0c966c"},
+ {file = "Cython-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53328a8af0806bebbdb48a4191883b11ee9d9dfb084d84f58fa5a8ab58baefc9"},
+ {file = "Cython-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5962e70b15e863e72bed6910e8c6ffef77d36cc98e2b31c474378f3b9e49b0e3"},
+ {file = "Cython-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9e69139f4e60ab14c50767a568612ea64d6907e9c8e0289590a170eb495e005f"},
+ {file = "Cython-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c40bdbcb2286f0aeeb5df9ce53d45da2d2a9b36a16b331cd0809d212d22a8fc7"},
+ {file = "Cython-3.0.0-cp312-cp312-win32.whl", hash = "sha256:8abb8915eb2e57fa53d918afe641c05d1bcc6ed1913682ec1f28de71f4e3f398"},
+ {file = "Cython-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:30a4bd2481e59bd7ab2539f835b78edc19fc455811e476916f56026b93afd28b"},
+ {file = "Cython-3.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0e1e4b7e4bfbf22fecfa5b852f0e499c442d4853b7ebd33ae37cdec9826ed5d8"},
+ {file = "Cython-3.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b00df42cdd1a285a64491ba23de08ab14169d3257c840428d40eb7e8e9979af"},
+ {file = "Cython-3.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:650d03ddddc08b051b4659778733f0f173ca7d327415755c05d265a6c1ba02fb"},
+ {file = "Cython-3.0.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4965f2ebade17166f21a508d66dd60d2a0b3a3b90abe3f72003baa17ae020dd6"},
+ {file = "Cython-3.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4123c8d03167803df31da6b39de167cb9c04ac0aa4e35d4e5aa9d08ad511b84d"},
+ {file = "Cython-3.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:296c53b6c0030cf82987eef163444e8d7631cc139d995f9d58679d9fd1ddbf31"},
+ {file = "Cython-3.0.0-cp36-cp36m-win32.whl", hash = "sha256:0d2c1e172f1c81bafcca703093608e10dc16e3e2d24c5644c17606c7fdb1792c"},
+ {file = "Cython-3.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bc816d8eb3686d6f8d165f4156bac18c1147e1035dc28a76742d0b7fb5b7c032"},
+ {file = "Cython-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8d86651347bbdbac1aca1824696c5e4c0a3b162946c422edcca2be12a03744d1"},
+ {file = "Cython-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84176bd04ce9f3cc8799b47ec6d1959fa1ea5e71424507df7bbf0b0915bbedef"},
+ {file = "Cython-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35abcf07b8277ec95bbe49a07b5c8760a2d941942ccfe759a94c8d2fe5602e9f"},
+ {file = "Cython-3.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a44d6b9a29b2bff38bb648577b2fcf6a68cf8b1783eee89c2eb749f69494b98d"},
+ {file = "Cython-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4dc6bbe7cf079db37f1ebb9b0f10d0d7f29e293bb8688e92d50b5ea7a91d82f3"},
+ {file = "Cython-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e28763e75e380b8be62b02266a7995a781997c97c119efbdccb8fb954bcd7574"},
+ {file = "Cython-3.0.0-cp37-cp37m-win32.whl", hash = "sha256:edae615cb4af51d5173e76ba9aea212424d025c57012e9cdf2f131f774c5ba71"},
+ {file = "Cython-3.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:20c604e974832aaf8b7a1f5455ee7274b34df62a35ee095cd7d2ed7e818e6c53"},
+ {file = "Cython-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c85fd2b1cbd9400d60ebe074795bb9a9188752f1612be3b35b0831a24879b91f"},
+ {file = "Cython-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:090256c687106932339f87f888b95f0d69c617bc9b18801555545b695d29d8ab"},
+ {file = "Cython-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec2a67a0a7d9d4399758c0657ca03e5912e37218859cfbf046242cc532bfb3b"},
+ {file = "Cython-3.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1cdd01ce45333bc264a218c6e183700d6b998f029233f586a53c9b13455c2d2"},
+ {file = "Cython-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecee663d2d50ca939fc5db81f2f8a219c2417b4651ad84254c50a03a9cb1aadd"},
+ {file = "Cython-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:30f10e79393b411af7677c270ea69807acb9fc30205c8ff25561f4deef780ec1"},
+ {file = "Cython-3.0.0-cp38-cp38-win32.whl", hash = "sha256:609777d3a7a0a23b225e84d967af4ad2485c8bdfcacef8037cf197e87d431ca0"},
+ {file = "Cython-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f4a6dfd42ae0a45797f50fc4f6add702abf46ab3e7cd61811a6c6a97a40e1a2"},
+ {file = "Cython-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2d8158277c8942c0b20ff4c074fe6a51c5b89e6ac60cef606818de8c92773596"},
+ {file = "Cython-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54e34f99b2a8c1e11478541b2822e6408c132b98b6b8f5ed89411e5e906631ea"},
+ {file = "Cython-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877d1c8745df59dd2061a0636c602729e9533ba13f13aa73a498f68662e1cbde"},
+ {file = "Cython-3.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204690be60f0ff32eb70b04f28ef0d1e50ffd7b3f77ba06a7dc2389ee3b848e0"},
+ {file = "Cython-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06fcb4628ccce2ba5abc8630adbeaf4016f63a359b4c6c3827b2d80e0673981c"},
+ {file = "Cython-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:090e24cfa31c926d0b13d8bb2ef48175acdd061ae1413343c94a2b12a4a4fa6f"},
+ {file = "Cython-3.0.0-cp39-cp39-win32.whl", hash = "sha256:4cd00f2158dc00f7f93a92444d0f663eda124c9c29bbbd658964f4e89c357fe8"},
+ {file = "Cython-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:5b4cc896d49ce2bae8d6a030f9a4c64965b59c38acfbf4617685e17f7fcf1731"},
+ {file = "Cython-3.0.0-py2.py3-none-any.whl", hash = "sha256:ff1aef1a03cfe293237c7a86ae9625b0411b2df30c53d1a7f29a8d381f38a1df"},
+ {file = "Cython-3.0.0.tar.gz", hash = "sha256:350b18f9673e63101dbbfcf774ee2f57c20ac4636d255741d76ca79016b1bd82"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "decorator"
+version = "5.1.1"
+description = "Decorators for Humans"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
+ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "dlinfo"
+version = "1.2.1"
+description = "Python wrapper for libc's dlinfo and dyld_find on Mac"
+optional = false
+python-versions = "*"
+files = [
+ {file = "dlinfo-1.2.1-py3-none-any.whl", hash = "sha256:a97d7cc66d997b4ac491f0e8068eb324790994834951a9beb5a4619835b361d9"},
+ {file = "dlinfo-1.2.1.tar.gz", hash = "sha256:5f6f43b47f3aa5fe12bd347cf536dc8fca6068c61a0a260e408bec7f6eb4bd38"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "facexlib"
+version = "0.3.0"
+description = "Basic face library"
+optional = false
+python-versions = "*"
+files = [
+ {file = "facexlib-0.3.0-py3-none-any.whl", hash = "sha256:245d58861537b820c616e8b3ef618ccfad2a24724a2d74be2b0542643c01a878"},
+ {file = "facexlib-0.3.0.tar.gz", hash = "sha256:7ae784a520eb52e05583e8bf9f68f77f45083239ac754d646d635017b49e7763"},
+]
+
+[package.dependencies]
+filterpy = "*"
+numba = "*"
+numpy = "*"
+opencv-python = "*"
+Pillow = "*"
+scipy = "*"
+torch = "*"
+torchvision = "*"
+tqdm = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "filelock"
+version = "3.12.2"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
+ {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "filterpy"
+version = "1.4.5"
+description = "Kalman filtering and optimal estimation library"
+optional = false
+python-versions = "*"
+files = [
+ {file = "filterpy-1.4.5.zip", hash = "sha256:4f2a4d39e4ea601b9ab42b2db08b5918a9538c168cff1c6895ae26646f3d73b1"},
+]
+
+[package.dependencies]
+matplotlib = "*"
+numpy = "*"
+scipy = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "flask"
+version = "2.3.2"
+description = "A simple framework for building complex web applications."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Flask-2.3.2-py3-none-any.whl", hash = "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0"},
+ {file = "Flask-2.3.2.tar.gz", hash = "sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef"},
+]
+
+[package.dependencies]
+blinker = ">=1.6.2"
+click = ">=8.1.3"
+itsdangerous = ">=2.1.2"
+Jinja2 = ">=3.1.2"
+Werkzeug = ">=2.3.3"
+
+[package.extras]
+async = ["asgiref (>=3.2)"]
+dotenv = ["python-dotenv"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "flatbuffers"
+version = "23.5.26"
+description = "The FlatBuffers serialization format for Python"
+optional = false
+python-versions = "*"
+files = [
+ {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"},
+ {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "fonttools"
+version = "4.42.1"
+description = "Tools to manipulate font files"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"},
+ {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"},
+ {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"},
+ {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"},
+ {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"},
+ {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"},
+ {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"},
+ {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"},
+ {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"},
+ {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"},
+ {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"},
+ {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"},
+ {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"},
+ {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"},
+ {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"},
+ {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"},
+ {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"},
+ {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"},
+ {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"},
+ {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"},
+ {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"},
+ {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"},
+ {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"},
+ {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"},
+ {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"},
+ {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"},
+ {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"},
+ {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"},
+ {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"},
+ {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"},
+ {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"},
+ {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"},
+ {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"},
+ {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"},
+]
+
+[package.extras]
+all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"]
+graphite = ["lz4 (>=1.7.4.2)"]
+interpolatable = ["munkres", "scipy"]
+lxml = ["lxml (>=4.0,<5)"]
+pathops = ["skia-pathops (>=0.5.0)"]
+plot = ["matplotlib"]
+repacker = ["uharfbuzz (>=0.23.0)"]
+symfont = ["sympy"]
+type1 = ["xattr"]
+ufo = ["fs (>=2.2.0,<3)"]
+unicode = ["unicodedata2 (>=15.0.0)"]
+woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "future"
+version = "0.18.3"
+description = "Clean single-source support for Python 3 and 2"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "gfpgan"
+version = "1.3.8"
+description = "GFPGAN aims at developing Practical Algorithms for Real-world Face Restoration"
+optional = false
+python-versions = "*"
+files = [
+ {file = "gfpgan-1.3.8-py3-none-any.whl", hash = "sha256:3d8386df6320aa9dfb0dd4cd09d9f8ed12ae0bbd9b2df257c3d21aefac5d8b85"},
+ {file = "gfpgan-1.3.8.tar.gz", hash = "sha256:21618b06ce8ea6230448cb526b012004f23a9ab956b55c833f69b9fc8a60c4f9"},
+]
+
+[package.dependencies]
+basicsr = ">=1.4.2"
+facexlib = ">=0.2.5"
+lmdb = "*"
+numpy = "*"
+opencv-python = "*"
+pyyaml = "*"
+scipy = "*"
+tb-nightly = "*"
+torch = ">=1.7"
+torchvision = "*"
+tqdm = "*"
+yapf = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "google-auth"
+version = "2.17.3"
+description = "Google Authentication Library"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
+files = [
+ {file = "google-auth-2.17.3.tar.gz", hash = "sha256:ce311e2bc58b130fddf316df57c9b3943c2a7b4f6ec31de9663a9333e4064efc"},
+ {file = "google_auth-2.17.3-py2.py3-none-any.whl", hash = "sha256:f586b274d3eb7bd932ea424b1c702a30e0393a2e2bc4ca3eae8263ffd8be229f"},
+]
+
+[package.dependencies]
+cachetools = ">=2.0.0,<6.0"
+pyasn1-modules = ">=0.2.1"
+rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""}
+six = ">=1.9.0"
+
+[package.extras]
+aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"]
+enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"]
+pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"]
+reauth = ["pyu2f (>=0.1.5)"]
+requests = ["requests (>=2.20.0,<3.0.0dev)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "google-auth-oauthlib"
+version = "1.0.0"
+description = "Google Authentication Library"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"},
+ {file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"},
+]
+
+[package.dependencies]
+google-auth = ">=2.15.0"
+requests-oauthlib = ">=0.7.0"
+
+[package.extras]
+tool = ["click (>=6.0.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "grpcio"
+version = "1.57.0"
+description = "HTTP/2-based RPC framework"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "grpcio-1.57.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6"},
+ {file = "grpcio-1.57.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649"},
+ {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f"},
+ {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a"},
+ {file = "grpcio-1.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019"},
+ {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527"},
+ {file = "grpcio-1.57.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca"},
+ {file = "grpcio-1.57.0-cp310-cp310-win32.whl", hash = "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb"},
+ {file = "grpcio-1.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56"},
+ {file = "grpcio-1.57.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652"},
+ {file = "grpcio-1.57.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e"},
+ {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e"},
+ {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b"},
+ {file = "grpcio-1.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e"},
+ {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d"},
+ {file = "grpcio-1.57.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a"},
+ {file = "grpcio-1.57.0-cp311-cp311-win32.whl", hash = "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe"},
+ {file = "grpcio-1.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0"},
+ {file = "grpcio-1.57.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf"},
+ {file = "grpcio-1.57.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5"},
+ {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2"},
+ {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73"},
+ {file = "grpcio-1.57.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0"},
+ {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc"},
+ {file = "grpcio-1.57.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2"},
+ {file = "grpcio-1.57.0-cp37-cp37m-win_amd64.whl", hash = "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98"},
+ {file = "grpcio-1.57.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51"},
+ {file = "grpcio-1.57.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0"},
+ {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6"},
+ {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941"},
+ {file = "grpcio-1.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f"},
+ {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06"},
+ {file = "grpcio-1.57.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79"},
+ {file = "grpcio-1.57.0-cp38-cp38-win32.whl", hash = "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb"},
+ {file = "grpcio-1.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16"},
+ {file = "grpcio-1.57.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b"},
+ {file = "grpcio-1.57.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6"},
+ {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b"},
+ {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e"},
+ {file = "grpcio-1.57.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5"},
+ {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9"},
+ {file = "grpcio-1.57.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37"},
+ {file = "grpcio-1.57.0-cp39-cp39-win32.whl", hash = "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766"},
+ {file = "grpcio-1.57.0-cp39-cp39-win_amd64.whl", hash = "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056"},
+ {file = "grpcio-1.57.0.tar.gz", hash = "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613"},
+]
+
+[package.extras]
+protobuf = ["grpcio-tools (>=1.57.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "humanfriendly"
+version = "10.0"
+description = "Human friendly output for text interfaces using Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
+ {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
+]
+
+[package.dependencies]
+pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "idna"
+version = "3.4"
+description = "Internationalized Domain Names in Applications (IDNA)"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
+ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "imageio"
+version = "2.31.1"
+description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "imageio-2.31.1-py3-none-any.whl", hash = "sha256:4106fb395ef7f8dc0262d6aa1bb03daba818445c381ca8b7d5dfc7a2089b04df"},
+ {file = "imageio-2.31.1.tar.gz", hash = "sha256:f8436a02af02fd63f272dab50f7d623547a38f0e04a4a73e2b02ae1b8b180f27"},
+]
+
+[package.dependencies]
+numpy = "*"
+pillow = ">=8.3.2"
+
+[package.extras]
+all-plugins = ["astropy", "av", "imageio-ffmpeg", "psutil", "tifffile"]
+all-plugins-pypy = ["av", "imageio-ffmpeg", "psutil", "tifffile"]
+build = ["wheel"]
+dev = ["black", "flake8", "fsspec[github]", "pytest", "pytest-cov"]
+docs = ["numpydoc", "pydata-sphinx-theme", "sphinx (<6)"]
+ffmpeg = ["imageio-ffmpeg", "psutil"]
+fits = ["astropy"]
+full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "itk", "numpydoc", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"]
+gdal = ["gdal"]
+itk = ["itk"]
+linting = ["black", "flake8"]
+pyav = ["av"]
+test = ["fsspec[github]", "pytest", "pytest-cov"]
+tifffile = ["tifffile"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "importlib-metadata"
+version = "6.8.0"
+description = "Read metadata from Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
+ {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
+]
+
+[package.dependencies]
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+perf = ["ipython"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "isodate"
+version = "0.6.1"
+description = "An ISO 8601 date/time/duration parser and formatter"
+optional = false
+python-versions = "*"
+files = [
+ {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"},
+ {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"},
+]
+
+[package.dependencies]
+six = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "itsdangerous"
+version = "2.1.2"
+description = "Safely pass data to untrusted environments and back."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"},
+ {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "jieba"
+version = "0.42.1"
+description = "Chinese Words Segmentation Utilities"
+optional = false
+python-versions = "*"
+files = [
+ {file = "jieba-0.42.1.tar.gz", hash = "sha256:055ca12f62674fafed09427f176506079bc135638a14e23e25be909131928db2"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "jinja2"
+version = "3.1.2"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
+ {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "joblib"
+version = "1.3.2"
+description = "Lightweight pipelining with Python functions"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"},
+ {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "jsonschema"
+version = "4.19.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"},
+ {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2023.7.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"},
+ {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"},
+]
+
+[package.dependencies]
+referencing = ">=0.28.0"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "kiwisolver"
+version = "1.4.4"
+description = "A fast implementation of the Cassowary constraint solver"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"},
+ {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"},
+ {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"},
+ {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"},
+ {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"},
+ {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"},
+ {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"},
+ {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"},
+ {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"},
+ {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"},
+ {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"},
+ {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"},
+ {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"},
+ {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"},
+ {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"},
+ {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"},
+ {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"},
+ {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"},
+ {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"},
+ {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"},
+ {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "language-tags"
+version = "1.2.0"
+description = "This project is a Python version of the language-tags Javascript project."
+optional = false
+python-versions = "*"
+files = [
+ {file = "language_tags-1.2.0-py3-none-any.whl", hash = "sha256:d815604622242fdfbbfd747b40c31213617fd03734a267f2e39ee4bd73c88722"},
+ {file = "language_tags-1.2.0.tar.gz", hash = "sha256:e934acba3e3dc85f867703eca421847a9ab7b7679b11b5d5cfd096febbf8bde6"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "lazy-loader"
+version = "0.3"
+description = "lazy_loader"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "lazy_loader-0.3-py3-none-any.whl", hash = "sha256:1e9e76ee8631e264c62ce10006718e80b2cfc74340d17d1031e0f84af7478554"},
+ {file = "lazy_loader-0.3.tar.gz", hash = "sha256:3b68898e34f5b2a29daaaac172c6555512d0f32074f147e2254e4a6d9d838f37"},
+]
+
+[package.extras]
+lint = ["pre-commit (>=3.3)"]
+test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "librosa"
+version = "0.10.1"
+description = "Python module for audio and music processing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "librosa-0.10.1-py3-none-any.whl", hash = "sha256:7ab91d9f5fcb75ea14848a05d3b1f825cf8d0c42ca160d19ae6874f2de2d8223"},
+ {file = "librosa-0.10.1.tar.gz", hash = "sha256:832f7d150d6dd08ed2aa08c0567a4be58330635c32ddd2208de9bc91300802c7"},
+]
+
+[package.dependencies]
+audioread = ">=2.1.9"
+decorator = ">=4.3.0"
+joblib = ">=0.14"
+lazy-loader = ">=0.1"
+msgpack = ">=1.0"
+numba = ">=0.51.0"
+numpy = ">=1.20.3,<1.22.0 || >1.22.0,<1.22.1 || >1.22.1,<1.22.2 || >1.22.2"
+pooch = ">=1.0"
+scikit-learn = ">=0.20.0"
+scipy = ">=1.2.0"
+soundfile = ">=0.12.1"
+soxr = ">=0.3.2"
+typing-extensions = ">=4.1.1"
+
+[package.extras]
+display = ["matplotlib (>=3.3.0)"]
+docs = ["ipython (>=7.0)", "matplotlib (>=3.3.0)", "mir-eval (>=0.5)", "numba (>=0.51)", "numpydoc", "presets", "sphinx (!=1.3.1)", "sphinx-gallery (>=0.7)", "sphinx-multiversion (>=0.2.3)", "sphinx-rtd-theme (>=1.2.0)", "sphinxcontrib-svg2pdfconverter"]
+tests = ["matplotlib (>=3.3.0)", "packaging (>=20.0)", "pytest", "pytest-cov", "pytest-mpl", "resampy (>=0.2.2)", "samplerate", "types-decorator"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "lit"
+version = "16.0.6"
+description = "A Software Testing Tool"
+optional = false
+python-versions = "*"
+files = [
+ {file = "lit-16.0.6.tar.gz", hash = "sha256:84623c9c23b6b14763d637f4e63e6b721b3446ada40bf7001d8fee70b8e77a9a"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "llvmlite"
+version = "0.40.1"
+description = "lightweight wrapper around basic LLVM functionality"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "llvmlite-0.40.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ce9b1c7a59936382ffde7871978cddcda14098e5a76d961e204523e5c372fb"},
+ {file = "llvmlite-0.40.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3673c53cb21c65d2ff3704962b5958e967c6fc0bd0cff772998face199e8d87b"},
+ {file = "llvmlite-0.40.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bba2747cf5b4954e945c287fe310b3fcc484e2a9d1b0c273e99eb17d103bb0e6"},
+ {file = "llvmlite-0.40.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbd5e82cc990e5a3e343a3bf855c26fdfe3bfae55225f00efd01c05bbda79918"},
+ {file = "llvmlite-0.40.1-cp310-cp310-win32.whl", hash = "sha256:09f83ea7a54509c285f905d968184bba00fc31ebf12f2b6b1494d677bb7dde9b"},
+ {file = "llvmlite-0.40.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b37297f3cbd68d14a97223a30620589d98ad1890e5040c9e5fc181063f4ed49"},
+ {file = "llvmlite-0.40.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a66a5bd580951751b4268f4c3bddcef92682814d6bc72f3cd3bb67f335dd7097"},
+ {file = "llvmlite-0.40.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:467b43836b388eaedc5a106d76761e388dbc4674b2f2237bc477c6895b15a634"},
+ {file = "llvmlite-0.40.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c23edd196bd797dc3a7860799054ea3488d2824ecabc03f9135110c2e39fcbc"},
+ {file = "llvmlite-0.40.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a36d9f244b6680cb90bbca66b146dabb2972f4180c64415c96f7c8a2d8b60a36"},
+ {file = "llvmlite-0.40.1-cp311-cp311-win_amd64.whl", hash = "sha256:5b3076dc4e9c107d16dc15ecb7f2faf94f7736cd2d5e9f4dc06287fd672452c1"},
+ {file = "llvmlite-0.40.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a7525db121f2e699809b539b5308228854ccab6693ecb01b52c44a2f5647e20"},
+ {file = "llvmlite-0.40.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:84747289775d0874e506f907a4513db889471607db19b04de97d144047fec885"},
+ {file = "llvmlite-0.40.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e35766e42acef0fe7d1c43169a8ffc327a47808fae6a067b049fe0e9bbf84dd5"},
+ {file = "llvmlite-0.40.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cda71de10a1f48416309e408ea83dab5bf36058f83e13b86a2961defed265568"},
+ {file = "llvmlite-0.40.1-cp38-cp38-win32.whl", hash = "sha256:96707ebad8b051bbb4fc40c65ef93b7eeee16643bd4d579a14d11578e4b7a647"},
+ {file = "llvmlite-0.40.1-cp38-cp38-win_amd64.whl", hash = "sha256:e44f854dc11559795bcdeaf12303759e56213d42dabbf91a5897aa2d8b033810"},
+ {file = "llvmlite-0.40.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f643d15aacd0b0b0dc8b74b693822ba3f9a53fa63bc6a178c2dba7cc88f42144"},
+ {file = "llvmlite-0.40.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39a0b4d0088c01a469a5860d2e2d7a9b4e6a93c0f07eb26e71a9a872a8cadf8d"},
+ {file = "llvmlite-0.40.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9329b930d699699846623054121ed105fd0823ed2180906d3b3235d361645490"},
+ {file = "llvmlite-0.40.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2dbbb8424037ca287983b115a29adf37d806baf7e1bf4a67bd2cffb74e085ed"},
+ {file = "llvmlite-0.40.1-cp39-cp39-win32.whl", hash = "sha256:e74e7bec3235a1e1c9ad97d897a620c5007d0ed80c32c84c1d787e7daa17e4ec"},
+ {file = "llvmlite-0.40.1-cp39-cp39-win_amd64.whl", hash = "sha256:ff8f31111bb99d135ff296757dc81ab36c2dee54ed4bd429158a96da9807c316"},
+ {file = "llvmlite-0.40.1.tar.gz", hash = "sha256:5cdb0d45df602099d833d50bd9e81353a5e036242d3c003c5b294fc61d1986b4"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "lmdb"
+version = "1.4.1"
+description = "Universal Python binding for the LMDB 'Lightning' Database"
+optional = false
+python-versions = "*"
+files = [
+ {file = "lmdb-1.4.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcdbe27f75da9b8f58815c6ac9a1f8fa2d7a8d42abc22abb664e089002d5ffa4"},
+ {file = "lmdb-1.4.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:032ce6f490caedbec642fc0a79114475e8520d1bf1e1465c6a12b8e5fe39022f"},
+ {file = "lmdb-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13c5c8504d419039d6617cee24941e420d648a5b15c4b21e6491821400e5750f"},
+ {file = "lmdb-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f8018a947608c4be0dc885c90f477a600be1b71285059a9c68280d36b3fb29b"},
+ {file = "lmdb-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:360ac42a8772f571fdd01156e0466d6be52eea1140556a138281b7c887916ae2"},
+ {file = "lmdb-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f683f3d9a1771f21a7788a9be98fae9f3ce13cb8d549d6074d0402f284572458"},
+ {file = "lmdb-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73332a830c72d76d57744cd2b29eca2c258bc406273ca4ee07dc9e48ae84d712"},
+ {file = "lmdb-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c178c5134e942256a830b0bca7bb052d3d7c645b4b8759d720ab49ec36b3aae"},
+ {file = "lmdb-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:12047c239ab6ccbbc9db99277aabcfe1c15b1cfc9ea33b92ab30ddd6f0823a10"},
+ {file = "lmdb-1.4.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:91930a2a7eb9acc4d687f9067d6f9ec83c9673bbee55823badbbee2f9a3e9970"},
+ {file = "lmdb-1.4.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1b106eb7a23b6a224bc7dfe2bd5a34c84973dda039965ae99106e10d22833dd9"},
+ {file = "lmdb-1.4.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d7779ccfacd5f4c62f28485dd2427b54d19dd7016000e6237816a3750287a82"},
+ {file = "lmdb-1.4.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c1f1eff7ae8d8d534309f05e274fd646dd1d4abf5157c59db59a54a55463371"},
+ {file = "lmdb-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b6354df94d241e8c0158f716902224109a5f3f7ed9a24447a25f968427f61d77"},
+ {file = "lmdb-1.4.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:64cf7470edfc45ff0369956e40a0784b5225097569299b91f893bd50fa336f52"},
+ {file = "lmdb-1.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3c15d344731507fcfddb911a86d325e867c5574751af28591e82ecf21aad1e5"},
+ {file = "lmdb-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:342550b86bb6275bfb89dbde9e48385da51d57124433bd464cd7681d0702f566"},
+ {file = "lmdb-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3a99a3859427fbc273ae1e932b3e7da946089757e74a05a24a19f5c4a1aba933"},
+ {file = "lmdb-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f71da9bd33fd17c9cdbe2bd4ce87f4b36b8f044927df4220bec4b03f209c78a2"},
+ {file = "lmdb-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e9ff50ad20d890bc63524230237a61b6eb3be96ad6a6ac475e8ba1a1f2c751f"},
+ {file = "lmdb-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81abf9475a62b7ced1ac0352967106b7ed1ac5d1c1a0d23ed24abe55a28f9884"},
+ {file = "lmdb-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:c9fa31743b447a3fbbbdaefc858de1c761568d855155dec54d5ad490f88856b6"},
+ {file = "lmdb-1.4.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:26ef8fa7bd34a64f78f5e16fa9bcce0fe2ad682dd26ef078f95a8847dacb1171"},
+ {file = "lmdb-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f5dc8a335f7925fd667d62a5e43bed3aa35959b32b233fe0112a6ef02e07877"},
+ {file = "lmdb-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ba5d78b0ff130b38a56b7161ceb7e27ba4364d827d2bbb251c24b06c28c64cd"},
+ {file = "lmdb-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3b84f6a349ed1bd3fa4e6c3c6b711d0389cc8d9206733cb92feffaf102998e0c"},
+ {file = "lmdb-1.4.1-pp27-pypy_73-macosx_10_7_x86_64.whl", hash = "sha256:a428e6b0e298290b91b7d0ce409f595c2c9027d7f2076c39ba006290b90d14cc"},
+ {file = "lmdb-1.4.1-pp27-pypy_73-win_amd64.whl", hash = "sha256:885d3f3bf51b9167d368e37b1f1277eabf595dceefd69a489bd81c1ffd3d8ffd"},
+ {file = "lmdb-1.4.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4bd8e49d5209c652b2caa18a3a4c30524025d7868d34b7bb249c42f7997da240"},
+ {file = "lmdb-1.4.1.tar.gz", hash = "sha256:1f4c76af24e907593487c904ef5eba1993beb38ed385af82adb25a858f2d658d"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "lxml"
+version = "4.9.3"
+description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
+files = [
+ {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"},
+ {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"},
+ {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"},
+ {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"},
+ {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"},
+ {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"},
+ {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"},
+ {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"},
+ {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"},
+ {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"},
+ {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"},
+ {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"},
+ {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"},
+ {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"},
+ {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"},
+ {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"},
+ {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"},
+ {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"},
+ {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"},
+ {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"},
+ {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"},
+ {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"},
+ {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"},
+ {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"},
+ {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"},
+ {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"},
+ {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"},
+ {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"},
+ {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"},
+ {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"},
+ {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"},
+ {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"},
+ {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"},
+ {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"},
+ {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"},
+ {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"},
+ {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"},
+ {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"},
+ {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"},
+ {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"},
+ {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"},
+ {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"},
+ {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"},
+ {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"},
+ {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"},
+ {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"},
+ {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"},
+ {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"},
+ {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"},
+ {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"},
+ {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"},
+ {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"},
+ {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"},
+ {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"},
+ {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"},
+ {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"},
+ {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"},
+ {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"},
+ {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"},
+ {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"},
+ {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"},
+ {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"},
+ {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"},
+ {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"},
+ {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"},
+ {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"},
+ {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"},
+ {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"},
+ {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"},
+ {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"},
+ {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"},
+ {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"},
+]
+
+[package.extras]
+cssselect = ["cssselect (>=0.7)"]
+html5 = ["html5lib"]
+htmlsoup = ["BeautifulSoup4"]
+source = ["Cython (>=0.29.35)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "markdown"
+version = "3.4.4"
+description = "Python implementation of John Gruber's Markdown."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"},
+ {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"},
+]
+
+[package.extras]
+docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"]
+testing = ["coverage", "pyyaml"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "markupsafe"
+version = "2.1.3"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
+ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "matplotlib"
+version = "3.7.2"
+description = "Python plotting package"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"},
+ {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"},
+ {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"},
+ {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"},
+ {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"},
+ {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"},
+ {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"},
+ {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"},
+ {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"},
+ {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"},
+ {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"},
+ {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"},
+ {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"},
+ {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"},
+ {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"},
+ {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"},
+ {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"},
+ {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"},
+ {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"},
+ {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"},
+ {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"},
+ {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"},
+ {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"},
+ {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"},
+ {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"},
+ {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"},
+ {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"},
+ {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"},
+ {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"},
+ {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"},
+ {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"},
+ {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"},
+ {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"},
+ {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"},
+ {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"},
+ {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"},
+ {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"},
+ {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"},
+ {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"},
+ {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"},
+ {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"},
+]
+
+[package.dependencies]
+contourpy = ">=1.0.1"
+cycler = ">=0.10"
+fonttools = ">=4.22.0"
+kiwisolver = ">=1.0.1"
+numpy = ">=1.20"
+packaging = ">=20.0"
+pillow = ">=6.2.0"
+pyparsing = ">=2.3.1,<3.1"
+python-dateutil = ">=2.7"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "mpmath"
+version = "1.3.0"
+description = "Python library for arbitrary-precision floating-point arithmetic"
+optional = false
+python-versions = "*"
+files = [
+ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"},
+ {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"},
+]
+
+[package.extras]
+develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"]
+docs = ["sphinx"]
+gmpy = ["gmpy2 (>=2.1.0a4)"]
+tests = ["pytest (>=4.6)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "msgpack"
+version = "1.0.5"
+description = "MessagePack serializer"
+optional = false
+python-versions = "*"
+files = [
+ {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9"},
+ {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198"},
+ {file = "msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81"},
+ {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7"},
+ {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3"},
+ {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b"},
+ {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c"},
+ {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd"},
+ {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a"},
+ {file = "msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea"},
+ {file = "msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a"},
+ {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0"},
+ {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898"},
+ {file = "msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a"},
+ {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a"},
+ {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705"},
+ {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"},
+ {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9"},
+ {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7"},
+ {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed"},
+ {file = "msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c"},
+ {file = "msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2"},
+ {file = "msgpack-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57"},
+ {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080"},
+ {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6"},
+ {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f"},
+ {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c"},
+ {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b"},
+ {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c"},
+ {file = "msgpack-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9"},
+ {file = "msgpack-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a"},
+ {file = "msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c"},
+ {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b"},
+ {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f"},
+ {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f"},
+ {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d"},
+ {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086"},
+ {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf"},
+ {file = "msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77"},
+ {file = "msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82"},
+ {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c"},
+ {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d"},
+ {file = "msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb"},
+ {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba"},
+ {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1"},
+ {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87"},
+ {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb"},
+ {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48"},
+ {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0"},
+ {file = "msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e"},
+ {file = "msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1"},
+ {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025"},
+ {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5"},
+ {file = "msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd"},
+ {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437"},
+ {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f"},
+ {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282"},
+ {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d"},
+ {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8"},
+ {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11"},
+ {file = "msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc"},
+ {file = "msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164"},
+ {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "networkx"
+version = "3.1"
+description = "Python package for creating and manipulating graphs and networks"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"},
+ {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"},
+]
+
+[package.extras]
+default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"]
+developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"]
+doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"]
+extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"]
+test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "numba"
+version = "0.57.1"
+description = "compiling Python code using LLVM"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "numba-0.57.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db8268eb5093cae2288942a8cbd69c9352f6fe6e0bfa0a9a27679436f92e4248"},
+ {file = "numba-0.57.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:643cb09a9ba9e1bd8b060e910aeca455e9442361e80fce97690795ff9840e681"},
+ {file = "numba-0.57.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:53e9fab973d9e82c9f8449f75994a898daaaf821d84f06fbb0b9de2293dd9306"},
+ {file = "numba-0.57.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c0602e4f896e6a6d844517c3ab434bc978e7698a22a733cc8124465898c28fa8"},
+ {file = "numba-0.57.1-cp310-cp310-win32.whl", hash = "sha256:3d6483c27520d16cf5d122868b79cad79e48056ecb721b52d70c126bed65431e"},
+ {file = "numba-0.57.1-cp310-cp310-win_amd64.whl", hash = "sha256:a32ee263649aa3c3587b833d6311305379529570e6c20deb0c6f4fb5bc7020db"},
+ {file = "numba-0.57.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c078f84b5529a7fdb8413bb33d5100f11ec7b44aa705857d9eb4e54a54ff505"},
+ {file = "numba-0.57.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e447c4634d1cc99ab50d4faa68f680f1d88b06a2a05acf134aa6fcc0342adeca"},
+ {file = "numba-0.57.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4838edef2df5f056cb8974670f3d66562e751040c448eb0b67c7e2fec1726649"},
+ {file = "numba-0.57.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9b17fbe4a69dcd9a7cd49916b6463cd9a82af5f84911feeb40793b8bce00dfa7"},
+ {file = "numba-0.57.1-cp311-cp311-win_amd64.whl", hash = "sha256:93df62304ada9b351818ba19b1cfbddaf72cd89348e81474326ca0b23bf0bae1"},
+ {file = "numba-0.57.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8e00ca63c5d0ad2beeb78d77f087b3a88c45ea9b97e7622ab2ec411a868420ee"},
+ {file = "numba-0.57.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ff66d5b022af6c7d81ddbefa87768e78ed4f834ab2da6ca2fd0d60a9e69b94f5"},
+ {file = "numba-0.57.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:60ec56386076e9eed106a87c96626d5686fbb16293b9834f0849cf78c9491779"},
+ {file = "numba-0.57.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c057ccedca95df23802b6ccad86bb318be624af45b5a38bb8412882be57a681"},
+ {file = "numba-0.57.1-cp38-cp38-win32.whl", hash = "sha256:5a82bf37444039c732485c072fda21a361790ed990f88db57fd6941cd5e5d307"},
+ {file = "numba-0.57.1-cp38-cp38-win_amd64.whl", hash = "sha256:9bcc36478773ce838f38afd9a4dfafc328d4ffb1915381353d657da7f6473282"},
+ {file = "numba-0.57.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae50c8c90c2ce8057f9618b589223e13faa8cbc037d8f15b4aad95a2c33a0582"},
+ {file = "numba-0.57.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9a1b2b69448e510d672ff9a6b18d2db9355241d93c6a77677baa14bec67dc2a0"},
+ {file = "numba-0.57.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3cf78d74ad9d289fbc1e5b1c9f2680fca7a788311eb620581893ab347ec37a7e"},
+ {file = "numba-0.57.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f47dd214adc5dcd040fe9ad2adbd2192133c9075d2189ce1b3d5f9d72863ef05"},
+ {file = "numba-0.57.1-cp39-cp39-win32.whl", hash = "sha256:a3eac19529956185677acb7f01864919761bfffbb9ae04bbbe5e84bbc06cfc2b"},
+ {file = "numba-0.57.1-cp39-cp39-win_amd64.whl", hash = "sha256:9587ba1bf5f3035575e45562ada17737535c6d612df751e811d702693a72d95e"},
+ {file = "numba-0.57.1.tar.gz", hash = "sha256:33c0500170d213e66d90558ad6aca57d3e03e97bb11da82e6d87ab793648cb17"},
+]
+
+[package.dependencies]
+llvmlite = "==0.40.*"
+numpy = ">=1.21,<1.25"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "numpy"
+version = "1.24.4"
+description = "Fundamental package for array computing in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"},
+ {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"},
+ {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"},
+ {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"},
+ {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"},
+ {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"},
+ {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"},
+ {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"},
+ {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"},
+ {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"},
+ {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"},
+ {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"},
+ {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"},
+ {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"},
+ {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"},
+ {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"},
+ {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"},
+ {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"},
+ {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"},
+ {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"},
+ {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"},
+ {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"},
+ {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"},
+ {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"},
+ {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cublas-cu11"
+version = "11.10.3.66"
+description = "CUBLAS native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-manylinux1_x86_64.whl", hash = "sha256:d32e4d75f94ddfb93ea0a5dda08389bcc65d8916a25cb9f37ac89edaeed3bded"},
+ {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-win_amd64.whl", hash = "sha256:8ac17ba6ade3ed56ab898a036f9ae0756f1e81052a317bf98f8c6d18dc3ae49e"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cuda-cupti-cu11"
+version = "11.7.101"
+description = "CUDA profiling tools runtime libs."
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_cupti_cu11-11.7.101-py3-none-manylinux1_x86_64.whl", hash = "sha256:e0cfd9854e1f2edaa36ca20d21cd0bdd5dcfca4e3b9e130a082e05b33b6c5895"},
+ {file = "nvidia_cuda_cupti_cu11-11.7.101-py3-none-win_amd64.whl", hash = "sha256:7cc5b8f91ae5e1389c3c0ad8866b3b016a175e827ea8f162a672990a402ab2b0"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cuda-nvrtc-cu11"
+version = "11.7.99"
+description = "NVRTC native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_nvrtc_cu11-11.7.99-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:9f1562822ea264b7e34ed5930567e89242d266448e936b85bc97a3370feabb03"},
+ {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:f7d9610d9b7c331fa0da2d1b2858a4a8315e6d49765091d28711c8946e7425e7"},
+ {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:f2effeb1309bdd1b3854fc9b17eaf997808f8b25968ce0c7070945c4265d64a3"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cuda-runtime-cu11"
+version = "11.7.99"
+description = "CUDA Runtime native Libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc768314ae58d2641f07eac350f40f99dcb35719c4faff4bc458a7cd2b119e31"},
+ {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:bc77fa59a7679310df9d5c70ab13c4e34c64ae2124dd1efd7e5474b71be125c7"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cudnn-cu11"
+version = "8.5.0.96"
+description = "cuDNN runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cudnn_cu11-8.5.0.96-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:402f40adfc6f418f9dae9ab402e773cfed9beae52333f6d86ae3107a1b9527e7"},
+ {file = "nvidia_cudnn_cu11-8.5.0.96-py3-none-manylinux1_x86_64.whl", hash = "sha256:71f8111eb830879ff2836db3cccf03bbd735df9b0d17cd93761732ac50a8a108"},
+]
+
+[package.dependencies]
+nvidia-cublas-cu11 = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cufft-cu11"
+version = "10.9.0.58"
+description = "CUFFT native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cufft_cu11-10.9.0.58-py3-none-manylinux1_x86_64.whl", hash = "sha256:222f9da70c80384632fd6035e4c3f16762d64ea7a843829cb278f98b3cb7dd81"},
+ {file = "nvidia_cufft_cu11-10.9.0.58-py3-none-win_amd64.whl", hash = "sha256:c4d316f17c745ec9c728e30409612eaf77a8404c3733cdf6c9c1569634d1ca03"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-curand-cu11"
+version = "10.2.10.91"
+description = "CURAND native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_curand_cu11-10.2.10.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:eecb269c970fa599a2660c9232fa46aaccbf90d9170b96c462e13bcb4d129e2c"},
+ {file = "nvidia_curand_cu11-10.2.10.91-py3-none-win_amd64.whl", hash = "sha256:f742052af0e1e75523bde18895a9ed016ecf1e5aa0ecddfcc3658fd11a1ff417"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cusolver-cu11"
+version = "11.4.0.1"
+description = "CUDA solver native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cusolver_cu11-11.4.0.1-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:72fa7261d755ed55c0074960df5904b65e2326f7adce364cbe4945063c1be412"},
+ {file = "nvidia_cusolver_cu11-11.4.0.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:700b781bfefd57d161443aff9ace1878584b93e0b2cfef3d6e9296d96febbf99"},
+ {file = "nvidia_cusolver_cu11-11.4.0.1-py3-none-win_amd64.whl", hash = "sha256:00f70b256add65f8c1eb3b6a65308795a93e7740f6df9e273eccbba770d370c4"},
+]
+
+[package.dependencies]
+nvidia-cublas-cu11 = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-cusparse-cu11"
+version = "11.7.4.91"
+description = "CUSPARSE native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cusparse_cu11-11.7.4.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:a3389de714db63321aa11fbec3919271f415ef19fda58aed7f2ede488c32733d"},
+ {file = "nvidia_cusparse_cu11-11.7.4.91-py3-none-win_amd64.whl", hash = "sha256:304a01599534f5186a8ed1c3756879282c72c118bc77dd890dc1ff868cad25b9"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-nccl-cu11"
+version = "2.14.3"
+description = "NVIDIA Collective Communication Library (NCCL) Runtime"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_nccl_cu11-2.14.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:5e5534257d1284b8e825bc3a182c6f06acd6eb405e9f89d49340e98cd8f136eb"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "nvidia-nvtx-cu11"
+version = "11.7.91"
+description = "NVIDIA Tools Extension"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_nvtx_cu11-11.7.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:b22c64eee426a62fc00952b507d6d29cf62b4c9df7a480fcc417e540e05fd5ac"},
+ {file = "nvidia_nvtx_cu11-11.7.91-py3-none-win_amd64.whl", hash = "sha256:dfd7fcb2a91742513027d63a26b757f38dd8b07fecac282c4d132a9d373ff064"},
+]
+
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "oauthlib"
+version = "3.2.2"
+description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"},
+ {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"},
+]
+
+[package.extras]
+rsa = ["cryptography (>=3.0.0)"]
+signals = ["blinker (>=1.4.0)"]
+signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "onnxruntime"
+version = "1.15.1"
+description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
+optional = false
+python-versions = "*"
+files = [
+ {file = "onnxruntime-1.15.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:baad59e6a763237fa39545325d29c16f98b8a45d2dfc524c67631e2e3ba44d16"},
+ {file = "onnxruntime-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:568c2db848f619a0a93e843c028e9fb4879929d40b04bd60f9ba6eb8d2e93421"},
+ {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69088d7784bb04dedfd9e883e2c96e4adf8ae0451acdd0abb78d68f59ecc6d9d"},
+ {file = "onnxruntime-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cef43737b2cd886d5d718d100f56ec78c9c476c5db5f8f946e95024978fe754"},
+ {file = "onnxruntime-1.15.1-cp310-cp310-win32.whl", hash = "sha256:79d7e65abb44a47c633ede8e53fe7b9756c272efaf169758c482c983cca98d7e"},
+ {file = "onnxruntime-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:8bc4c47682933a7a2c79808688aad5f12581305e182be552de50783b5438e6bd"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:652b2cb777f76446e3cc41072dd3d1585a6388aeff92b9de656724bc22e241e4"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89b86dbed15740abc385055a29c9673a212600248d702737ce856515bdeddc88"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed5cdd9ee748149a57f4cdfa67187a0d68f75240645a3c688299dcd08742cc98"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f748cce6a70ed38c19658615c55f4eedb9192765a4e9c4bd2682adfe980698d"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-win32.whl", hash = "sha256:e0312046e814c40066e7823da58075992d51364cbe739eeeb2345ec440c3ac59"},
+ {file = "onnxruntime-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:f0980969689cb956c22bd1318b271e1be260060b37f3ddd82c7d63bd7f2d9a79"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:345986cfdbd6f4b20a89b6a6cd9abd3e2ced2926ae0b6e91fefa8149f95c0f09"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d7b3ad75e040f1e95757f69826a11051737b31584938a26d466a0234c6de98"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3603d07b829bcc1c14963a76103e257aade8861eb208173b300cc26e118ec2f8"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3df0625b9295daf1f7409ea55f72e1eeb38d54f5769add53372e79ddc3cf98d"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-win32.whl", hash = "sha256:f68b47fdf1a0406c0292f81ac993e2a2ae3e8b166b436d590eb221f64e8e187a"},
+ {file = "onnxruntime-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:52d762d297cc3f731f54fa65a3e329b813164970671547bef6414d0ed52765c9"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:99228f9f03dc1fc8af89a28c9f942e8bd3e97e894e263abe1a32e4ddb1f6363b"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45db7f96febb0cf23e3af147f35c4f8de1a37dd252d1cef853c242c2780250cd"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bafc112a36db25c821b90ab747644041cb4218f6575889775a2c12dd958b8c3"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985693d18f2d46aa34fd44d7f65ff620660b2c8fa4b8ec365c2ca353f0fbdb27"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-win32.whl", hash = "sha256:708eb31b0c04724bf0f01c1309a9e69bbc09b85beb750e5662c8aed29f1ff9fd"},
+ {file = "onnxruntime-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:73d6de4c42dfde1e9dbea04773e6dc23346c8cda9c7e08c6554fafc97ac60138"},
+]
+
+[package.dependencies]
+coloredlogs = "*"
+flatbuffers = "*"
+numpy = ">=1.21.6"
+packaging = "*"
+protobuf = "*"
+sympy = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "opencv-python"
+version = "4.8.0.76"
+description = "Wrapper package for OpenCV python bindings."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "opencv-python-4.8.0.76.tar.gz", hash = "sha256:56d84c43ce800938b9b1ec74b33942b2edbcef3f70c2754eb9bfe5dff1ee3ace"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:67bce4b9aad307c98a9a07c6afb7de3a4e823c1f4991d6d8e88e229e7dfeee59"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:48eb3121d809a873086d6677565e3ac963e6946110d13cd115533fa70e2aa2eb"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93871871b1c9d6b125cddd45b0638a2fa01ee9fd37f5e428823f750e404f2f15"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcb4944211acf13742dbfd9d3a11dc4e36353ffa1746f2c7dcd6a01c32d1376"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-win32.whl", hash = "sha256:b2349dc9f97ed6c9ba163d0a7a24bcef9695a3e216cd143e92f1b9659c5d9a49"},
+ {file = "opencv_python-4.8.0.76-cp37-abi3-win_amd64.whl", hash = "sha256:ba32cfa75a806abd68249699d34420737d27b5678553387fc5768747a6492147"},
+]
+
+[package.dependencies]
+numpy = [
+ {version = ">=1.21.2", markers = "python_version >= \"3.10\""},
+ {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""},
+ {version = ">=1.23.5", markers = "python_version >= \"3.11\""},
+ {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""},
+ {version = ">=1.17.0", markers = "python_version >= \"3.7\""},
+ {version = ">=1.17.3", markers = "python_version >= \"3.8\""},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "opencv-python-headless"
+version = "4.8.0.76"
+description = "Wrapper package for OpenCV python bindings."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "opencv-python-headless-4.8.0.76.tar.gz", hash = "sha256:bc15726187dae26d8a08777faf6bc71d38f20c785c102677f58ba0e935003afb"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:f85d2e3b9d952db35d31f9db8882d073c903921b72b8db1cfed8bbc75e8d3e63"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:8ee3bf1c9086493c340c6a87899f1c7778d729de92bce8560b8c31ab8a9cdf79"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c675b8dec6298ba6a1eec2ce24077a393b4236a043f68dfacb06bf594354ce06"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:220d2e292fa45ef0582aab730460bbc15cfe61f2089208167a372ccf76f01e21"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-win32.whl", hash = "sha256:df0608de207ae9b094ad9eaf1a475cf6e9a069fb12cd289d4a18cefdab2f8aa8"},
+ {file = "opencv_python_headless-4.8.0.76-cp37-abi3-win_amd64.whl", hash = "sha256:9c094faf6ec7bd360244647b26ebdf8f54edec1d9292cb9179fff9badcca7be8"},
+]
+
+[package.dependencies]
+numpy = [
+ {version = ">=1.21.2", markers = "python_version >= \"3.10\""},
+ {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""},
+ {version = ">=1.23.5", markers = "python_version >= \"3.11\""},
+ {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""},
+ {version = ">=1.17.0", markers = "python_version >= \"3.7\""},
+ {version = ">=1.17.3", markers = "python_version >= \"3.8\""},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "openjtalk"
+version = "0.3.0.dev3"
+description = "A python wrapper for OpenJTalk"
+optional = false
+python-versions = "*"
+files = [
+ {file = "openjtalk-0.3.0.dev3-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:5cc67a123aed2ea25e4bd6e894fb4e73f47f7ca21ac2033d625b19029f583085"},
+ {file = "openjtalk-0.3.0.dev3-cp310-cp310-win_amd64.whl", hash = "sha256:852609e579c379489a1239d81ad3690363337b077dd0c1dac644cfcb0fa1f949"},
+ {file = "openjtalk-0.3.0.dev3-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:f5508acb589b82a03db5a01a138031d5e8e2da87e862fbfc27c74bf541d26bf1"},
+ {file = "openjtalk-0.3.0.dev3-cp311-cp311-win_amd64.whl", hash = "sha256:f4bade3531e08cc4588ec1983f6bb6c3acf0260081e28b8c5663d9855c9a2a49"},
+ {file = "openjtalk-0.3.0.dev3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:18b824705aafb7ef3a67b9c897b5196b478789f87b6ec3dd5a7adf468fa23bcc"},
+ {file = "openjtalk-0.3.0.dev3-cp38-cp38-win_amd64.whl", hash = "sha256:4b57e80367a0dcfa25c3f0339cdf419158a211226b2bfa77cc8f44c25e63f729"},
+ {file = "openjtalk-0.3.0.dev3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:9bf62a99bb069e658e49613159924e7463764ddc5cc0af754503f4aeeebd14ad"},
+ {file = "openjtalk-0.3.0.dev3-cp39-cp39-win_amd64.whl", hash = "sha256:44698ad23c39d4f2efceacd86e10b00622c5872fa5a36e2bd3f0d48c77605961"},
+ {file = "openjtalk-0.3.0.dev3.tar.gz", hash = "sha256:0f03a09ef6daa461aba469270b508c0a76a9dcdf3ede73949e538dc949c68a6c"},
+]
+
+[package.dependencies]
+cython = ">=0.21.0"
+numpy = ">=1.20.0"
+
+[package.extras]
+docs = ["Jinja2 (>=3.0.1)", "ipython", "jupyter", "nbsphinx (>=0.8.6)", "pandoc", "sphinx-rtd-theme"]
+lint = ["black (>=19.19b0,<=20.8)", "click (<8.1.0)", "flake8 (>=3.7,<4)", "flake8-bugbear", "isort (>=4.3,<5.2.0)", "mypy (<=0.910)", "pysen", "types-decorator", "types-setuptools"]
+marine = ["marine (>=0.0.5)"]
+test = ["pytest", "scipy"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "packaging"
+version = "23.1"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
+ {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "phonemizer"
+version = "3.2.1"
+description = "Simple text to phones converter for multiple languages"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "phonemizer-3.2.1-py3-none-any.whl", hash = "sha256:65eef55cd180c1f0be245f68de12bd6014a102ecce0ed8af2584fda853c75ac7"},
+ {file = "phonemizer-3.2.1.tar.gz", hash = "sha256:068f85f85a8a9adc638a3787aeacaf71a53e47578b12d773c097433500cd892b"},
+]
+
+[package.dependencies]
+attrs = ">=18.1"
+dlinfo = "*"
+joblib = "*"
+segments = "*"
+typing-extensions = "*"
+
+[package.extras]
+doc = ["sphinx", "sphinx-rtd-theme"]
+tests = ["pytest"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pillow"
+version = "10.0.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"},
+ {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"},
+ {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"},
+ {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"},
+ {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"},
+ {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"},
+ {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"},
+ {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"},
+ {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"},
+ {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"},
+ {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"},
+ {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"},
+ {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"},
+ {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"},
+ {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"},
+ {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"},
+ {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"},
+ {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"},
+ {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"},
+ {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"},
+ {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"},
+ {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"},
+ {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"},
+ {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"},
+ {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"},
+ {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"},
+ {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"},
+ {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"},
+ {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"},
+ {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"},
+ {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"},
+ {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"},
+ {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"},
+ {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"},
+ {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"},
+ {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"},
+ {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"},
+ {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"},
+ {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"},
+ {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"},
+ {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"},
+ {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"},
+ {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"},
+ {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"},
+ {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"},
+ {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"},
+ {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"},
+ {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"},
+ {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"},
+ {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"},
+ {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"},
+ {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"},
+ {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"},
+ {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"},
+ {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"},
+ {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "platformdirs"
+version = "3.10.0"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
+ {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pooch"
+version = "1.7.0"
+description = "\"Pooch manages your Python library's sample data files: it automatically downloads and stores them in a local directory, with support for versioning and corruption checks.\""
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pooch-1.7.0-py3-none-any.whl", hash = "sha256:74258224fc33d58f53113cf955e8d51bf01386b91492927d0d1b6b341a765ad7"},
+ {file = "pooch-1.7.0.tar.gz", hash = "sha256:f174a1041b6447f0eef8860f76d17f60ed2f857dc0efa387a7f08228af05d998"},
+]
+
+[package.dependencies]
+packaging = ">=20.0"
+platformdirs = ">=2.5.0"
+requests = ">=2.19.0"
+
+[package.extras]
+progress = ["tqdm (>=4.41.0,<5.0.0)"]
+sftp = ["paramiko (>=2.7.0)"]
+xxhash = ["xxhash (>=1.4.3)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "proces"
+version = "0.1.6"
+description = "text preprocess."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "proces-0.1.6-py3-none-any.whl", hash = "sha256:6d6fefcb2a83bf26e1f0d35ac1d1c22b988d5161ccd01d83440544780a294d9e"},
+ {file = "proces-0.1.6.tar.gz", hash = "sha256:a319bdf4b1724d080371f87febf4fd511d387dc78185d91687b607fa289cdce2"},
+]
+
+[package.dependencies]
+"ruamel.yaml" = ">=0.16.5"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "protobuf"
+version = "4.24.1"
+description = ""
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "protobuf-4.24.1-cp310-abi3-win32.whl", hash = "sha256:d414199ca605eeb498adc4d2ba82aedc0379dca4a7c364ff9bc9a179aa28e71b"},
+ {file = "protobuf-4.24.1-cp310-abi3-win_amd64.whl", hash = "sha256:5906c5e79ff50fe38b2d49d37db5874e3c8010826f2362f79996d83128a8ed9b"},
+ {file = "protobuf-4.24.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:970c701ee16788d74f3de20938520d7a0aebc7e4fff37096a48804c80d2908cf"},
+ {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fc361148e902949dcb953bbcb148c99fe8f8854291ad01107e4120361849fd0e"},
+ {file = "protobuf-4.24.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:5d32363d14aca6e5c9e9d5918ad8fb65b091b6df66740ae9de50ac3916055e43"},
+ {file = "protobuf-4.24.1-cp37-cp37m-win32.whl", hash = "sha256:df015c47d6855b8efa0b9be706c70bf7f050a4d5ac6d37fb043fbd95157a0e25"},
+ {file = "protobuf-4.24.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d4af4fd9e9418e819be30f8df2a16e72fbad546a7576ac7f3653be92a6966d30"},
+ {file = "protobuf-4.24.1-cp38-cp38-win32.whl", hash = "sha256:302e8752c760549ed4c7a508abc86b25d46553c81989343782809e1a062a2ef9"},
+ {file = "protobuf-4.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:06437f0d4bb0d5f29e3d392aba69600188d4be5ad1e0a3370e581a9bf75a3081"},
+ {file = "protobuf-4.24.1-cp39-cp39-win32.whl", hash = "sha256:0b2b224e9541fe9f046dd7317d05f08769c332b7e4c54d93c7f0f372dedb0b1a"},
+ {file = "protobuf-4.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd39b9094a4cc003a1f911b847ab379f89059f478c0b611ba1215053e295132e"},
+ {file = "protobuf-4.24.1-py3-none-any.whl", hash = "sha256:55dd644adc27d2a624339332755fe077c7f26971045b469ebb9732a69ce1f2ca"},
+ {file = "protobuf-4.24.1.tar.gz", hash = "sha256:44837a5ed9c9418ad5d502f89f28ba102e9cd172b6668bc813f21716f9273348"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pyasn1"
+version = "0.5.0"
+description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+files = [
+ {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"},
+ {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pyasn1-modules"
+version = "0.3.0"
+description = "A collection of ASN.1-based protocols modules"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+files = [
+ {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"},
+ {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"},
+]
+
+[package.dependencies]
+pyasn1 = ">=0.4.6,<0.6.0"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pycparser"
+version = "2.21"
+description = "C parser in Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pylatexenc"
+version = "2.10"
+description = "Simple LaTeX parser providing latex-to-unicode and unicode-to-latex conversion"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pylatexenc-2.10.tar.gz", hash = "sha256:3dd8fd84eb46dc30bee1e23eaab8d8fb5a7f507347b23e5f38ad9675c84f40d3"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pymatting"
+version = "1.1.8"
+description = "Python package for alpha matting."
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "PyMatting-1.1.8-py3-none-any.whl", hash = "sha256:40f650c4ff86fc4598488f67a2343ff11465df82f177b61edc34548b9a086202"},
+ {file = "PyMatting-1.1.8.tar.gz", hash = "sha256:a73508ef0874996831dfd284e3bc63151a09484d789fd10edc03f49b31532acc"},
+]
+
+[package.dependencies]
+numba = "!=0.49.0"
+numpy = ">=1.16.0"
+pillow = ">=5.2.0"
+scipy = ">=1.1.0"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pyparsing"
+version = "3.0.9"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+optional = false
+python-versions = ">=3.6.8"
+files = [
+ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
+ {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
+]
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pypinyin"
+version = "0.49.0"
+description = "汉字拼音转换模块/工具."
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
+files = [
+ {file = "pypinyin-0.49.0-py2.py3-none-any.whl", hash = "sha256:3791f5b647e446866e6b5d3a63942ecbaeb29b49fed268a9d9a4982241c35fe0"},
+ {file = "pypinyin-0.49.0.tar.gz", hash = "sha256:a5d61a79c5f48f6b4a422f010c20d48fcd53c705784df4aa80e329493219a4be"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pypinyin-dict"
+version = "0.6.0"
+description = "使用 pinyin-data 和 phrase-pinyin-data 中的拼音数据文件覆盖 pypinyin 中的自带拼音数据,实现只使用某个或某些拼音数据文件中的拼音数据的需求"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
+files = [
+ {file = "pypinyin-dict-0.6.0.tar.gz", hash = "sha256:d441a212b31d597f1b531b8f704f9896b53ca82cbe33e744614a452b86591fee"},
+ {file = "pypinyin_dict-0.6.0-py2.py3-none-any.whl", hash = "sha256:e8287138d0ded3f5029733d886a80a8bd2bed7d1a80b53683b5ba673a9a9d762"},
+]
+
+[package.dependencies]
+pypinyin = "*"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pyreadline3"
+version = "3.4.1"
+description = "A python implementation of GNU readline."
+optional = false
+python-versions = "*"
+files = [
+ {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"},
+ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "python-dateutil"
+version = "2.8.2"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
+ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pywavelets"
+version = "1.4.1"
+description = "PyWavelets, wavelet transform module"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "PyWavelets-1.4.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:d854411eb5ee9cb4bc5d0e66e3634aeb8f594210f6a1bed96dbed57ec70f181c"},
+ {file = "PyWavelets-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:231b0e0b1cdc1112f4af3c24eea7bf181c418d37922a67670e9bf6cfa2d544d4"},
+ {file = "PyWavelets-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:754fa5085768227c4f4a26c1e0c78bc509a266d9ebd0eb69a278be7e3ece943c"},
+ {file = "PyWavelets-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da7b9c006171be1f9ddb12cc6e0d3d703b95f7f43cb5e2c6f5f15d3233fcf202"},
+ {file = "PyWavelets-1.4.1-cp310-cp310-win32.whl", hash = "sha256:67a0d28a08909f21400cb09ff62ba94c064882ffd9e3a6b27880a111211d59bd"},
+ {file = "PyWavelets-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:91d3d393cffa634f0e550d88c0e3f217c96cfb9e32781f2960876f1808d9b45b"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:64c6bac6204327321db30b775060fbe8e8642316e6bff17f06b9f34936f88875"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f19327f2129fb7977bc59b966b4974dfd72879c093e44a7287500a7032695de"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad987748f60418d5f4138db89d82ba0cb49b086e0cbb8fd5c3ed4a814cfb705e"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:875d4d620eee655346e3589a16a73790cf9f8917abba062234439b594e706784"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-win32.whl", hash = "sha256:7231461d7a8eb3bdc7aa2d97d9f67ea5a9f8902522818e7e2ead9c2b3408eeb1"},
+ {file = "PyWavelets-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:daf0aa79842b571308d7c31a9c43bc99a30b6328e6aea3f50388cd8f69ba7dbc"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:ab7da0a17822cd2f6545626946d3b82d1a8e106afc4b50e3387719ba01c7b966"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:578af438a02a86b70f1975b546f68aaaf38f28fb082a61ceb799816049ed18aa"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb5ca8d11d3f98e89e65796a2125be98424d22e5ada360a0dbabff659fca0fc"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:058b46434eac4c04dd89aeef6fa39e4b6496a951d78c500b6641fd5b2cc2f9f4"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-win32.whl", hash = "sha256:de7cd61a88a982edfec01ea755b0740e94766e00a1ceceeafef3ed4c85c605cd"},
+ {file = "PyWavelets-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:7ab8d9db0fe549ab2ee0bea61f614e658dd2df419d5b75fba47baa761e95f8f2"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:23bafd60350b2b868076d976bdd92f950b3944f119b4754b1d7ff22b7acbf6c6"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0e56cd7a53aed3cceca91a04d62feb3a0aca6725b1912d29546c26f6ea90426"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030670a213ee8fefa56f6387b0c8e7d970c7f7ad6850dc048bd7c89364771b9b"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-win32.whl", hash = "sha256:47cac4fa25bed76a45bc781a293c26ac63e8eaae9eb8f9be961758d22b58649c"},
+ {file = "PyWavelets-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:88aa5449e109d8f5e7f0adef85f7f73b1ab086102865be64421a3a3d02d277f4"},
+ {file = "PyWavelets-1.4.1.tar.gz", hash = "sha256:6437af3ddf083118c26d8f97ab43b0724b956c9f958e9ea788659f6a2834ba93"},
+]
+
+[package.dependencies]
+numpy = ">=1.17.3"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "pyyaml"
+version = "6.0.1"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "rdflib"
+version = "7.0.0"
+description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information."
+optional = false
+python-versions = ">=3.8.1,<4.0.0"
+files = [
+ {file = "rdflib-7.0.0-py3-none-any.whl", hash = "sha256:0438920912a642c866a513de6fe8a0001bd86ef975057d6962c79ce4771687cd"},
+ {file = "rdflib-7.0.0.tar.gz", hash = "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae"},
+]
+
+[package.dependencies]
+isodate = ">=0.6.0,<0.7.0"
+pyparsing = ">=2.1.0,<4"
+
+[package.extras]
+berkeleydb = ["berkeleydb (>=18.1.0,<19.0.0)"]
+html = ["html5lib (>=1.0,<2.0)"]
+lxml = ["lxml (>=4.3.0,<5.0.0)"]
+networkx = ["networkx (>=2.0.0,<3.0.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "referencing"
+version = "0.30.2"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"},
+ {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "regex"
+version = "2023.8.8"
+description = "Alternative regular expression module, to replace re."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"},
+ {file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61"},
+ {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570"},
+ {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab"},
+ {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2"},
+ {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90"},
+ {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db"},
+ {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7"},
+ {file = "regex-2023.8.8-cp310-cp310-win32.whl", hash = "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb"},
+ {file = "regex-2023.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b"},
+ {file = "regex-2023.8.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71"},
+ {file = "regex-2023.8.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef"},
+ {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46"},
+ {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357"},
+ {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a"},
+ {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559"},
+ {file = "regex-2023.8.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177"},
+ {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf"},
+ {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6"},
+ {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208"},
+ {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7"},
+ {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd"},
+ {file = "regex-2023.8.8-cp311-cp311-win32.whl", hash = "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8"},
+ {file = "regex-2023.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb"},
+ {file = "regex-2023.8.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61"},
+ {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c"},
+ {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3"},
+ {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217"},
+ {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56"},
+ {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235"},
+ {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b"},
+ {file = "regex-2023.8.8-cp36-cp36m-win32.whl", hash = "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7"},
+ {file = "regex-2023.8.8-cp36-cp36m-win_amd64.whl", hash = "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236"},
+ {file = "regex-2023.8.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116"},
+ {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a"},
+ {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca"},
+ {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8"},
+ {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac"},
+ {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684"},
+ {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7"},
+ {file = "regex-2023.8.8-cp37-cp37m-win32.whl", hash = "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3"},
+ {file = "regex-2023.8.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921"},
+ {file = "regex-2023.8.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675"},
+ {file = "regex-2023.8.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9"},
+ {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280"},
+ {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a"},
+ {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e"},
+ {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504"},
+ {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586"},
+ {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882"},
+ {file = "regex-2023.8.8-cp38-cp38-win32.whl", hash = "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7"},
+ {file = "regex-2023.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be"},
+ {file = "regex-2023.8.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3"},
+ {file = "regex-2023.8.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033"},
+ {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470"},
+ {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a"},
+ {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34"},
+ {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9"},
+ {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf"},
+ {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6"},
+ {file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"},
+ {file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"},
+ {file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "rembg"
+version = "2.0.50"
+description = "Remove image background"
+optional = false
+python-versions = ">=3.8, <3.12"
+files = [
+ {file = "rembg-2.0.50-py3-none-any.whl", hash = "sha256:55153e475c394da8dbe8c148fcace5907a602db5bb7425c26dd7c7a3a22ac6a3"},
+ {file = "rembg-2.0.50.tar.gz", hash = "sha256:6ccb7f19ba6545ac05654aa85eadfbcc0ab576b89b9eefd9948613b94212f835"},
+]
+
+[package.dependencies]
+numpy = "*"
+onnxruntime = "*"
+opencv-python-headless = "*"
+pillow = "*"
+pooch = "*"
+pymatting = "*"
+scikit-image = "*"
+scipy = "*"
+tqdm = "*"
+
+[package.extras]
+cli = ["aiohttp", "asyncer", "click", "fastapi", "filetype", "gradio", "python-multipart", "uvicorn", "watchdog"]
+dev = ["bandit", "black", "flake8", "imagehash", "isort", "mypy", "pytest", "setuptools", "twine", "wheel"]
+gpu = ["onnxruntime-gpu"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "requests"
+version = "2.31.0"
+description = "Python HTTP for Humans."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
+ {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
+]
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<3"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "requests-oauthlib"
+version = "1.3.1"
+description = "OAuthlib authentication support for Requests."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"},
+ {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"},
+]
+
+[package.dependencies]
+oauthlib = ">=3.0.0"
+requests = ">=2.0.0"
+
+[package.extras]
+rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "rfc3986"
+version = "1.5.0"
+description = "Validating URI References per RFC 3986"
+optional = false
+python-versions = "*"
+files = [
+ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
+ {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
+]
+
+[package.extras]
+idna2008 = ["idna"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "rpds-py"
+version = "0.9.2"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"},
+ {file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"},
+ {file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"},
+ {file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"},
+ {file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"},
+ {file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"},
+ {file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"},
+ {file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"},
+ {file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"},
+ {file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"},
+ {file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"},
+ {file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"},
+ {file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"},
+ {file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"},
+ {file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"},
+ {file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"},
+ {file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "rsa"
+version = "4.9"
+description = "Pure-Python RSA implementation"
+optional = false
+python-versions = ">=3.6,<4"
+files = [
+ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
+ {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
+]
+
+[package.dependencies]
+pyasn1 = ">=0.1.3"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "ruamel-yaml"
+version = "0.17.32"
+description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "ruamel.yaml-0.17.32-py3-none-any.whl", hash = "sha256:23cd2ed620231677564646b0c6a89d138b6822a0d78656df7abda5879ec4f447"},
+ {file = "ruamel.yaml-0.17.32.tar.gz", hash = "sha256:ec939063761914e14542972a5cba6d33c23b0859ab6342f61cf070cfc600efc2"},
+]
+
+[package.dependencies]
+"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""}
+
+[package.extras]
+docs = ["ryd"]
+jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "ruamel-yaml-clib"
+version = "0.2.7"
+description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"},
+ {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "scikit-image"
+version = "0.21.0"
+description = "Image processing in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "scikit_image-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:978ac3302252155a8556cdfe067bad2d18d5ccef4e91c2f727bc564ed75566bc"},
+ {file = "scikit_image-0.21.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:82c22e008527e5ee26ab08e3ce919998ef164d538ff30b9e5764b223cfda06b1"},
+ {file = "scikit_image-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd29d2631d3e975c377066acfc1f4cb2cc95e2257cf70e7fedfcb96441096e88"},
+ {file = "scikit_image-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6c12925ceb9f3aede555921e26642d601b2d37d1617002a2636f2cb5178ae2f"},
+ {file = "scikit_image-0.21.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f538d4de77e4f3225d068d9ea2965bed3f7dda7f457a8f89634fa22ffb9ad8c"},
+ {file = "scikit_image-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ec9bab6920ac43037d7434058b67b5778d42c60f67b8679239f48a471e7ed6f8"},
+ {file = "scikit_image-0.21.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:a54720430dba833ffbb6dedd93d9f0938c5dd47d20ab9ba3e4e61c19d95f6f19"},
+ {file = "scikit_image-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e40dd102da14cdadc09210f930b4556c90ff8f99cd9d8bcccf9f73a86c44245"},
+ {file = "scikit_image-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff5719c7eb99596a39c3e1d9b564025bae78ecf1da3ee6842d34f6965b5f1474"},
+ {file = "scikit_image-0.21.0-cp311-cp311-win_amd64.whl", hash = "sha256:146c3824253eee9ff346c4ad10cb58376f91aefaf4a4bb2fe11aa21691f7de76"},
+ {file = "scikit_image-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e1b09f81a99c9c390215929194847b3cd358550b4b65bb6e42c5393d69cb74a"},
+ {file = "scikit_image-0.21.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:9f7b5fb4a22f0d5ae0fa13beeb887c925280590145cd6d8b2630794d120ff7c7"},
+ {file = "scikit_image-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4814033717f0b6491fee252facb9df92058d6a72ab78dd6408a50f3915a88b8"},
+ {file = "scikit_image-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0d6ed6502cca0c9719c444caafa0b8cda0f9e29e01ca42f621a240073284be"},
+ {file = "scikit_image-0.21.0-cp38-cp38-win_amd64.whl", hash = "sha256:9194cb7bc21215fde6c1b1e9685d312d2aa8f65ea9736bc6311126a91c860032"},
+ {file = "scikit_image-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54df1ddc854f37a912d42bc724e456e86858107e94048a81a27720bc588f9937"},
+ {file = "scikit_image-0.21.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:c01e3ab0a1fabfd8ce30686d4401b7ed36e6126c9d4d05cb94abf6bdc46f7ac9"},
+ {file = "scikit_image-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ef5d8d1099317b7b315b530348cbfa68ab8ce32459de3c074d204166951025c"},
+ {file = "scikit_image-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b1e96c59cab640ca5c5b22c501524cfaf34cbe0cb51ba73bd9a9ede3fb6e1d"},
+ {file = "scikit_image-0.21.0-cp39-cp39-win_amd64.whl", hash = "sha256:9cffcddd2a5594c0a06de2ae3e1e25d662745a26f94fda31520593669677c010"},
+ {file = "scikit_image-0.21.0.tar.gz", hash = "sha256:b33e823c54e6f11873ea390ee49ef832b82b9f70752c8759efd09d5a4e3d87f0"},
+]
+
+[package.dependencies]
+imageio = ">=2.27"
+lazy_loader = ">=0.2"
+networkx = ">=2.8"
+numpy = ">=1.21.1"
+packaging = ">=21"
+pillow = ">=9.0.1"
+PyWavelets = ">=1.1.1"
+scipy = ">=1.8"
+tifffile = ">=2022.8.12"
+
+[package.extras]
+build = ["Cython (>=0.29.32)", "build", "meson-python (>=0.13)", "ninja", "numpy (>=1.21.1)", "packaging (>=21)", "pythran", "setuptools (>=67)", "spin (==0.3)", "wheel"]
+data = ["pooch (>=1.6.0)"]
+default = ["PyWavelets (>=1.1.1)", "imageio (>=2.27)", "lazy_loader (>=0.2)", "networkx (>=2.8)", "numpy (>=1.21.1)", "packaging (>=21)", "pillow (>=9.0.1)", "scipy (>=1.8)", "tifffile (>=2022.8.12)"]
+developer = ["pre-commit", "rtoml"]
+docs = ["dask[array] (>=2022.9.2)", "ipykernel", "ipywidgets", "kaleido", "matplotlib (>=3.5)", "myst-parser", "numpydoc (>=1.5)", "pandas (>=1.5)", "plotly (>=5.10)", "pooch (>=1.6)", "pydata-sphinx-theme (>=0.13)", "pytest-runner", "scikit-learn (>=0.24.0)", "seaborn (>=0.11)", "sphinx (>=5.0)", "sphinx-copybutton", "sphinx-gallery (>=0.11)", "sphinx_design (>=0.3)", "tifffile (>=2022.8.12)"]
+optional = ["SimpleITK", "astropy (>=5.0)", "cloudpickle (>=0.2.1)", "dask[array] (>=2021.1.0)", "matplotlib (>=3.5)", "pooch (>=1.6.0)", "pyamg", "scikit-learn (>=0.24.0)"]
+test = ["asv", "matplotlib (>=3.5)", "pooch (>=1.6.0)", "pytest (>=7.0)", "pytest-cov (>=2.11.0)", "pytest-faulthandler", "pytest-localserver"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "scikit-learn"
+version = "1.3.0"
+description = "A set of python modules for machine learning and data mining"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "scikit-learn-1.3.0.tar.gz", hash = "sha256:8be549886f5eda46436b6e555b0e4873b4f10aa21c07df45c4bc1735afbccd7a"},
+ {file = "scikit_learn-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981287869e576d42c682cf7ca96af0c6ac544ed9316328fd0d9292795c742cf5"},
+ {file = "scikit_learn-1.3.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:436aaaae2c916ad16631142488e4c82f4296af2404f480e031d866863425d2a2"},
+ {file = "scikit_learn-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7e28d8fa47a0b30ae1bd7a079519dd852764e31708a7804da6cb6f8b36e3630"},
+ {file = "scikit_learn-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae80c08834a473d08a204d966982a62e11c976228d306a2648c575e3ead12111"},
+ {file = "scikit_learn-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:552fd1b6ee22900cf1780d7386a554bb96949e9a359999177cf30211e6b20df6"},
+ {file = "scikit_learn-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79970a6d759eb00a62266a31e2637d07d2d28446fca8079cf9afa7c07b0427f8"},
+ {file = "scikit_learn-1.3.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:850a00b559e636b23901aabbe79b73dc604b4e4248ba9e2d6e72f95063765603"},
+ {file = "scikit_learn-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee04835fb016e8062ee9fe9074aef9b82e430504e420bff51e3e5fffe72750ca"},
+ {file = "scikit_learn-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d953531f5d9f00c90c34fa3b7d7cfb43ecff4c605dac9e4255a20b114a27369"},
+ {file = "scikit_learn-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:151ac2bf65ccf363664a689b8beafc9e6aae36263db114b4ca06fbbbf827444a"},
+ {file = "scikit_learn-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a885a9edc9c0a341cab27ec4f8a6c58b35f3d449c9d2503a6fd23e06bbd4f6a"},
+ {file = "scikit_learn-1.3.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:9877af9c6d1b15486e18a94101b742e9d0d2f343d35a634e337411ddb57783f3"},
+ {file = "scikit_learn-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c470f53cea065ff3d588050955c492793bb50c19a92923490d18fcb637f6383a"},
+ {file = "scikit_learn-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6e2d7389542eae01077a1ee0318c4fec20c66c957f45c7aac0c6eb0fe3c612"},
+ {file = "scikit_learn-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:3a11936adbc379a6061ea32fa03338d4ca7248d86dd507c81e13af428a5bc1db"},
+ {file = "scikit_learn-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:998d38fcec96584deee1e79cd127469b3ad6fefd1ea6c2dfc54e8db367eb396b"},
+ {file = "scikit_learn-1.3.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ded35e810438a527e17623ac6deae3b360134345b7c598175ab7741720d7ffa7"},
+ {file = "scikit_learn-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8102d5036e28d08ab47166b48c8d5e5810704daecf3a476a4282d562be9a28"},
+ {file = "scikit_learn-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7617164951c422747e7c32be4afa15d75ad8044f42e7d70d3e2e0429a50e6718"},
+ {file = "scikit_learn-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:1d54fb9e6038284548072df22fd34777e434153f7ffac72c8596f2d6987110dd"},
+]
+
+[package.dependencies]
+joblib = ">=1.1.1"
+numpy = ">=1.17.3"
+scipy = ">=1.5.0"
+threadpoolctl = ">=2.0.0"
+
+[package.extras]
+benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"]
+docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"]
+examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"]
+tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "scipy"
+version = "1.11.2"
+description = "Fundamental algorithms for scientific computing in Python"
+optional = false
+python-versions = "<3.13,>=3.9"
+files = [
+ {file = "scipy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2b997a5369e2d30c97995dcb29d638701f8000d04df01b8e947f206e5d0ac788"},
+ {file = "scipy-1.11.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:95763fbda1206bec41157582bea482f50eb3702c85fffcf6d24394b071c0e87a"},
+ {file = "scipy-1.11.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e367904a0fec76433bf3fbf3e85bf60dae8e9e585ffd21898ab1085a29a04d16"},
+ {file = "scipy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d690e1ca993c8f7ede6d22e5637541217fc6a4d3f78b3672a6fe454dbb7eb9a7"},
+ {file = "scipy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d2b813bfbe8dec6a75164523de650bad41f4405d35b0fa24c2c28ae07fcefb20"},
+ {file = "scipy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:afdb0d983f6135d50770dd979df50bf1c7f58b5b33e0eb8cf5c73c70600eae1d"},
+ {file = "scipy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d9886f44ef8c9e776cb7527fb01455bf4f4a46c455c4682edc2c2cc8cd78562"},
+ {file = "scipy-1.11.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1342ca385c673208f32472830c10110a9dcd053cf0c4b7d4cd7026d0335a6c1d"},
+ {file = "scipy-1.11.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b133f237bd8ba73bad51bc12eb4f2d84cbec999753bf25ba58235e9fc2096d80"},
+ {file = "scipy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aeb87661de987f8ec56fa6950863994cd427209158255a389fc5aea51fa7055"},
+ {file = "scipy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90d3b1364e751d8214e325c371f0ee0dd38419268bf4888b2ae1040a6b266b2a"},
+ {file = "scipy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:f73102f769ee06041a3aa26b5841359b1a93cc364ce45609657751795e8f4a4a"},
+ {file = "scipy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa4909c6c20c3d91480533cddbc0e7c6d849e7d9ded692918c76ce5964997898"},
+ {file = "scipy-1.11.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ac74b1512d38718fb6a491c439aa7b3605b96b1ed3be6599c17d49d6c60fca18"},
+ {file = "scipy-1.11.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8425fa963a32936c9773ee3ce44a765d8ff67eed5f4ac81dc1e4a819a238ee9"},
+ {file = "scipy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:542a757e2a6ec409e71df3d8fd20127afbbacb1c07990cb23c5870c13953d899"},
+ {file = "scipy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea932570b1c2a30edafca922345854ff2cd20d43cd9123b6dacfdecebfc1a80b"},
+ {file = "scipy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:4447ad057d7597476f9862ecbd9285bbf13ba9d73ce25acfa4e4b11c6801b4c9"},
+ {file = "scipy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b0620240ef445b5ddde52460e6bc3483b7c9c750275369379e5f609a1050911c"},
+ {file = "scipy-1.11.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f28f1f6cfeb48339c192efc6275749b2a25a7e49c4d8369a28b6591da02fbc9a"},
+ {file = "scipy-1.11.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:214cdf04bbae7a54784f8431f976704ed607c4bc69ba0d5d5d6a9df84374df76"},
+ {file = "scipy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10eb6af2f751aa3424762948e5352f707b0dece77288206f227864ddf675aca0"},
+ {file = "scipy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0f3261f14b767b316d7137c66cc4f33a80ea05841b9c87ad83a726205b901423"},
+ {file = "scipy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:2c91cf049ffb5575917f2a01da1da082fd24ed48120d08a6e7297dfcac771dcd"},
+ {file = "scipy-1.11.2.tar.gz", hash = "sha256:b29318a5e39bd200ca4381d80b065cdf3076c7d7281c5e36569e99273867f61d"},
+]
+
+[package.dependencies]
+numpy = ">=1.21.6,<1.28.0"
+
+[package.extras]
+dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"]
+doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"]
+test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "segments"
+version = "2.2.1"
+description = ""
+optional = false
+python-versions = "*"
+files = [
+ {file = "segments-2.2.1-py2.py3-none-any.whl", hash = "sha256:069860ae5a499ad7bd86e23ee52250a16e61ba3474c17e515b16d494ac1423c1"},
+ {file = "segments-2.2.1.tar.gz", hash = "sha256:515ae188f21d24e420d48ad45689edc747d961d6b52fde22e47500a8d85f2741"},
+]
+
+[package.dependencies]
+clldutils = ">=1.7.3"
+csvw = ">=1.5.6"
+regex = "*"
+
+[package.extras]
+dev = ["flake8", "twine", "wheel"]
+test = ["pytest (>=5)", "pytest-cov", "pytest-mock"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "setuptools"
+version = "68.1.2"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"},
+ {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"},
+]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "soundfile"
+version = "0.12.1"
+description = "An audio library based on libsndfile, CFFI and NumPy"
+optional = false
+python-versions = "*"
+files = [
+ {file = "soundfile-0.12.1-py2.py3-none-any.whl", hash = "sha256:828a79c2e75abab5359f780c81dccd4953c45a2c4cd4f05ba3e233ddf984b882"},
+ {file = "soundfile-0.12.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:d922be1563ce17a69582a352a86f28ed8c9f6a8bc951df63476ffc310c064bfa"},
+ {file = "soundfile-0.12.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:bceaab5c4febb11ea0554566784bcf4bc2e3977b53946dda2b12804b4fe524a8"},
+ {file = "soundfile-0.12.1-py2.py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:2dc3685bed7187c072a46ab4ffddd38cef7de9ae5eb05c03df2ad569cf4dacbc"},
+ {file = "soundfile-0.12.1-py2.py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:074247b771a181859d2bc1f98b5ebf6d5153d2c397b86ee9e29ba602a8dfe2a6"},
+ {file = "soundfile-0.12.1-py2.py3-none-win32.whl", hash = "sha256:59dfd88c79b48f441bbf6994142a19ab1de3b9bb7c12863402c2bc621e49091a"},
+ {file = "soundfile-0.12.1-py2.py3-none-win_amd64.whl", hash = "sha256:0d86924c00b62552b650ddd28af426e3ff2d4dc2e9047dae5b3d8452e0a49a77"},
+ {file = "soundfile-0.12.1.tar.gz", hash = "sha256:e8e1017b2cf1dda767aef19d2fd9ee5ebe07e050d430f77a0a7c66ba08b8cdae"},
+]
+
+[package.dependencies]
+cffi = ">=1.0"
+
+[package.extras]
+numpy = ["numpy"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "soxr"
+version = "0.3.6"
+description = "High quality, one-dimensional sample-rate conversion library"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "soxr-0.3.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8f64bc45a30ee6d9765cc4b1fdb6b9d5ec7d2880fc42a2e968c662ed3abe83c7"},
+ {file = "soxr-0.3.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8fe418fcee2173422b5c25ca4d9e03a86dd9d08f1502b0077987e2018ac943df"},
+ {file = "soxr-0.3.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9074ee0901057353455febc5fe91a83dae1f97ade4e96acc8b95bd3d70cb495"},
+ {file = "soxr-0.3.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0b01688e7e591411a3499a62427a87236be31c84d6a88afd381947568f445df"},
+ {file = "soxr-0.3.6-cp310-cp310-win_amd64.whl", hash = "sha256:03834c82977dc8976a183e22dfc9dd0f65198f416ac79f6bb13310e63c795662"},
+ {file = "soxr-0.3.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:97a89e3798f22bd04c475b30c041ee2f2e223effb4f80a71d4f5e278f7939138"},
+ {file = "soxr-0.3.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:705af37f7a63d3abecf9121bff392241636b403bcf6e232fb527d0b108aa8700"},
+ {file = "soxr-0.3.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e73f8b9fb5ac3ad26155a6c789284bea1de98701c184e0ecb9cb328e9f81dfc2"},
+ {file = "soxr-0.3.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1add0aeed67f2396d7b4cefa36887ba8db1a185791f085c12aafa82e96d6fdf"},
+ {file = "soxr-0.3.6-cp311-cp311-win_amd64.whl", hash = "sha256:ba651652a64623a61ea86717357dcbf4d71f7f3695da979056ca257890f47d10"},
+ {file = "soxr-0.3.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c17f5efa78575afdbb854afbead11be5b209340e0ba801073ea4af31eeb567e7"},
+ {file = "soxr-0.3.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:475f86acd92e97275b86940afabf0f108252b6a684fc724cef8019308d234162"},
+ {file = "soxr-0.3.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f5d31d750886651137664cf55283e96a6f324d914d137f758d339d08a18347d"},
+ {file = "soxr-0.3.6-cp37-cp37m-win_amd64.whl", hash = "sha256:15277be23858ae9e1eeaec8151bbcd41ebf70c35ea067bb5e897f6834804256c"},
+ {file = "soxr-0.3.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac7da6054eff748f414cfaa8172249c492da7e88dde6aa97bfb2272d87727060"},
+ {file = "soxr-0.3.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dd1874aa176b5ae755f26c5bd7d9d45217839719a4343862d2fe72e50c57dd16"},
+ {file = "soxr-0.3.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c40a25ae9520d7752e7ece07c3ec2bc58f30893c20a58c9d7a5311e7499290"},
+ {file = "soxr-0.3.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ad635ee478635efca9457b811bba373272319b45a1941d7f9d9ac8c2e98b3bc"},
+ {file = "soxr-0.3.6-cp38-cp38-win_amd64.whl", hash = "sha256:dcf107a32d971e329b330a8f2026fedb118e39f5d549f65743184f8ec5d38204"},
+ {file = "soxr-0.3.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:385a37d39813e1d633229bcd94ab6bd76b27b779d38f2f6cbc390926f3965d31"},
+ {file = "soxr-0.3.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a78c61bf65b2e9d5612cbcab449a4a070ea84a18ff0757a840e0fa49b574225"},
+ {file = "soxr-0.3.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79872546786c3d05ff90260197863811532823fcfb58aeb647e916c6aa57299d"},
+ {file = "soxr-0.3.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c72ab44bfd72ecadb0a29e38487c241eb69a9867d3476e528c64e957fc06ff7"},
+ {file = "soxr-0.3.6-cp39-cp39-win_amd64.whl", hash = "sha256:2b2dd2e2625b4b98360cd1607d72e4bd2eac60de3a18244b8a4d45f9168a4541"},
+ {file = "soxr-0.3.6.tar.gz", hash = "sha256:6b3d98da77353b5bbb4401cef83cec7f1538844dc27c7badf89c2855b43f42b4"},
+]
+
+[package.dependencies]
+numpy = "*"
+
+[package.extras]
+docs = ["linkify-it-py", "myst-parser", "sphinx", "sphinx-book-theme"]
+test = ["pytest"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "sympy"
+version = "1.12"
+description = "Computer algebra system (CAS) in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"},
+ {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"},
+]
+
+[package.dependencies]
+mpmath = ">=0.19"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tabulate"
+version = "0.9.0"
+description = "Pretty-print tabular data"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"},
+ {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"},
+]
+
+[package.extras]
+widechars = ["wcwidth"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tb-nightly"
+version = "2.14.0a20230522"
+description = "TensorBoard lets you watch Tensors Flow"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tb_nightly-2.14.0a20230522-py3-none-any.whl", hash = "sha256:6a6f396133291cd5d5ecde017aaa4db2306289913b2f98bf537f2ddb12d74aba"},
+]
+
+[package.dependencies]
+absl-py = ">=0.4"
+google-auth = ">=1.6.3,<3"
+google-auth-oauthlib = ">=0.5,<1.1"
+grpcio = ">=1.48.2"
+markdown = ">=2.6.8"
+numpy = ">=1.12.0"
+protobuf = ">=3.19.6"
+requests = ">=2.21.0,<3"
+setuptools = ">=41.0.0"
+tensorboard-data-server = ">=0.7.0,<0.8.0"
+werkzeug = ">=1.0.1"
+wheel = ">=0.26"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tensorboard-data-server"
+version = "0.7.1"
+description = "Fast data loading for TensorBoard"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tensorboard_data_server-0.7.1-py3-none-any.whl", hash = "sha256:9938bd39f5041797b33921066fba0eab03a0dd10d1887a05e62ae58841ad4c3f"},
+ {file = "tensorboard_data_server-0.7.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:be8d016a1aa394e6198280d4a3dc37898f56467310c5f5e617cac10a783e055a"},
+ {file = "tensorboard_data_server-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:255c02b7f5b03dd5c0a88c928e563441ff39e1d4b4a234cdbe09f016e53d9594"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "threadpoolctl"
+version = "3.2.0"
+description = "threadpoolctl"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "threadpoolctl-3.2.0-py3-none-any.whl", hash = "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032"},
+ {file = "threadpoolctl-3.2.0.tar.gz", hash = "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tifffile"
+version = "2023.8.12"
+description = "Read and write TIFF files"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "tifffile-2023.8.12-py3-none-any.whl", hash = "sha256:d1ef06461a947a6800ba6121b330b54a57fb9cbf7e5bc0adab8307081297d66b"},
+ {file = "tifffile-2023.8.12.tar.gz", hash = "sha256:824956b6d974b9d346aae59932bea862a2ad18fcc2b1a820b6941b7f6ddb2bca"},
+]
+
+[package.dependencies]
+numpy = "*"
+
+[package.extras]
+all = ["defusedxml", "fsspec", "imagecodecs (>=2023.8.12)", "lxml", "matplotlib", "zarr"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "torch"
+version = "2.0.1"
+description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "torch-2.0.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8ced00b3ba471856b993822508f77c98f48a458623596a4c43136158781e306a"},
+ {file = "torch-2.0.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:359bfaad94d1cda02ab775dc1cc386d585712329bb47b8741607ef6ef4950747"},
+ {file = "torch-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:7c84e44d9002182edd859f3400deaa7410f5ec948a519cc7ef512c2f9b34d2c4"},
+ {file = "torch-2.0.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:567f84d657edc5582d716900543e6e62353dbe275e61cdc36eda4929e46df9e7"},
+ {file = "torch-2.0.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:787b5a78aa7917465e9b96399b883920c88a08f4eb63b5a5d2d1a16e27d2f89b"},
+ {file = "torch-2.0.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:e617b1d0abaf6ced02dbb9486803abfef0d581609b09641b34fa315c9c40766d"},
+ {file = "torch-2.0.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b6019b1de4978e96daa21d6a3ebb41e88a0b474898fe251fd96189587408873e"},
+ {file = "torch-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:dbd68cbd1cd9da32fe5d294dd3411509b3d841baecb780b38b3b7b06c7754434"},
+ {file = "torch-2.0.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:ef654427d91600129864644e35deea761fb1fe131710180b952a6f2e2207075e"},
+ {file = "torch-2.0.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:25aa43ca80dcdf32f13da04c503ec7afdf8e77e3a0183dd85cd3e53b2842e527"},
+ {file = "torch-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5ef3ea3d25441d3957348f7e99c7824d33798258a2bf5f0f0277cbcadad2e20d"},
+ {file = "torch-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0882243755ff28895e8e6dc6bc26ebcf5aa0911ed81b2a12f241fc4b09075b13"},
+ {file = "torch-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:f66aa6b9580a22b04d0af54fcd042f52406a8479e2b6a550e3d9f95963e168c8"},
+ {file = "torch-2.0.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:1adb60d369f2650cac8e9a95b1d5758e25d526a34808f7448d0bd599e4ae9072"},
+ {file = "torch-2.0.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:1bcffc16b89e296826b33b98db5166f990e3b72654a2b90673e817b16c50e32b"},
+ {file = "torch-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:e10e1597f2175365285db1b24019eb6f04d53dcd626c735fc502f1e8b6be9875"},
+ {file = "torch-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:423e0ae257b756bb45a4b49072046772d1ad0c592265c5080070e0767da4e490"},
+ {file = "torch-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8742bdc62946c93f75ff92da00e3803216c6cce9b132fbca69664ca38cfb3e18"},
+ {file = "torch-2.0.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:c62df99352bd6ee5a5a8d1832452110435d178b5164de450831a3a8cc14dc680"},
+ {file = "torch-2.0.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:671a2565e3f63b8fe8e42ae3e36ad249fe5e567435ea27b94edaa672a7d0c416"},
+]
+
+[package.dependencies]
+filelock = "*"
+jinja2 = "*"
+networkx = "*"
+nvidia-cublas-cu11 = {version = "11.10.3.66", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-cupti-cu11 = {version = "11.7.101", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-nvrtc-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-runtime-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cudnn-cu11 = {version = "8.5.0.96", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cufft-cu11 = {version = "10.9.0.58", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-curand-cu11 = {version = "10.2.10.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cusolver-cu11 = {version = "11.4.0.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cusparse-cu11 = {version = "11.7.4.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-nccl-cu11 = {version = "2.14.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-nvtx-cu11 = {version = "11.7.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+sympy = "*"
+triton = {version = "2.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+typing-extensions = "*"
+
+[package.extras]
+opt-einsum = ["opt-einsum (>=3.3)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "torchvision"
+version = "0.15.2"
+description = "image and video datasets and models for torch deep learning"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "torchvision-0.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7754088774e810c5672b142a45dcf20b1bd986a5a7da90f8660c43dc43fb850c"},
+ {file = "torchvision-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37eb138e13f6212537a3009ac218695483a635c404b6cc1d8e0d0d978026a86d"},
+ {file = "torchvision-0.15.2-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:54143f7cc0797d199b98a53b7d21c3f97615762d4dd17ad45a41c7e80d880e73"},
+ {file = "torchvision-0.15.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:1eefebf5fbd01a95fe8f003d623d941601c94b5cec547b420da89cb369d9cf96"},
+ {file = "torchvision-0.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:96fae30c5ca8423f4b9790df0f0d929748e32718d88709b7b567d2f630c042e3"},
+ {file = "torchvision-0.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5f35f6bd5bcc4568e6522e4137fa60fcc72f4fa3e615321c26cd87e855acd398"},
+ {file = "torchvision-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:757505a0ab2be7096cb9d2bf4723202c971cceddb72c7952a7e877f773de0f8a"},
+ {file = "torchvision-0.15.2-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:012ad25cfd9019ff9b0714a168727e3845029be1af82296ff1e1482931fa4b80"},
+ {file = "torchvision-0.15.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b02a7ffeaa61448737f39a4210b8ee60234bda0515a0c0d8562f884454105b0f"},
+ {file = "torchvision-0.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:10be76ceded48329d0a0355ac33da131ee3993ff6c125e4a02ab34b5baa2472c"},
+ {file = "torchvision-0.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f12415b686dba884fb086f53ac803f692be5a5cdd8a758f50812b30fffea2e4"},
+ {file = "torchvision-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:31211c01f8b8ec33b8a638327b5463212e79a03e43c895f88049f97af1bd12fd"},
+ {file = "torchvision-0.15.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c55f9889e436f14b4f84a9c00ebad0d31f5b4626f10cf8018e6c676f92a6d199"},
+ {file = "torchvision-0.15.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:9a192f2aa979438f23c20e883980b23d13268ab9f819498774a6d2eb021802c2"},
+ {file = "torchvision-0.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:c07071bc8d02aa8fcdfe139ab6a1ef57d3b64c9e30e84d12d45c9f4d89fb6536"},
+ {file = "torchvision-0.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4790260fcf478a41c7ecc60a6d5200a88159fdd8d756e9f29f0f8c59c4a67a68"},
+ {file = "torchvision-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:987ab62225b4151a11e53fd06150c5258ced24ac9d7c547e0e4ab6fbca92a5ce"},
+ {file = "torchvision-0.15.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:63df26673e66cba3f17e07c327a8cafa3cce98265dbc3da329f1951d45966838"},
+ {file = "torchvision-0.15.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b85f98d4cc2f72452f6792ab4463a3541bc5678a8cdd3da0e139ba2fe8b56d42"},
+ {file = "torchvision-0.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:07c462524cc1bba5190c16a9d47eac1fca024d60595a310f23c00b4ffff18b30"},
+]
+
+[package.dependencies]
+numpy = "*"
+pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0"
+requests = "*"
+torch = "2.0.1"
+
+[package.extras]
+scipy = ["scipy"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "tqdm"
+version = "4.66.1"
+description = "Fast, Extensible Progress Meter"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"},
+ {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.extras]
+dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"]
+notebook = ["ipywidgets (>=6)"]
+slack = ["slack-sdk"]
+telegram = ["requests"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "triton"
+version = "2.0.0"
+description = "A language and compiler for custom Deep Learning operations"
+optional = false
+python-versions = "*"
+files = [
+ {file = "triton-2.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38806ee9663f4b0f7cd64790e96c579374089e58f49aac4a6608121aa55e2505"},
+ {file = "triton-2.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:226941c7b8595219ddef59a1fdb821e8c744289a132415ddd584facedeb475b1"},
+ {file = "triton-2.0.0-1-cp36-cp36m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4c9fc8c89874bc48eb7e7b2107a9b8d2c0bf139778637be5bfccb09191685cfd"},
+ {file = "triton-2.0.0-1-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d2684b6a60b9f174f447f36f933e9a45f31db96cb723723ecd2dcfd1c57b778b"},
+ {file = "triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef"},
+ {file = "triton-2.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74f118c12b437fb2ca25e1a04759173b517582fcf4c7be11913316c764213656"},
+ {file = "triton-2.0.0-1-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9618815a8da1d9157514f08f855d9e9ff92e329cd81c0305003eb9ec25cc5add"},
+ {file = "triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a"},
+ {file = "triton-2.0.0-1-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e3e13aa8b527c9b642e3a9defcc0fbd8ffbe1c80d8ac8c15a01692478dc64d8a"},
+ {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"},
+ {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"},
+ {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"},
+ {file = "triton-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fedce6a381901b1547e0e7e1f2546e4f65dca6d91e2d8a7305a2d1f5551895be"},
+ {file = "triton-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75834f27926eab6c7f00ce73aaf1ab5bfb9bec6eb57ab7c0bfc0a23fac803b4c"},
+ {file = "triton-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0117722f8c2b579cd429e0bee80f7731ae05f63fe8e9414acd9a679885fcbf42"},
+ {file = "triton-2.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcd9be5d0c2e45d2b7e6ddc6da20112b6862d69741576f9c3dbaf941d745ecae"},
+ {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"},
+ {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"},
+]
+
+[package.dependencies]
+cmake = "*"
+filelock = "*"
+lit = "*"
+torch = "*"
+
+[package.extras]
+tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"]
+tutorials = ["matplotlib", "pandas", "tabulate"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "typing-extensions"
+version = "4.7.1"
+description = "Backported and Experimental Type Hints for Python 3.7+"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
+ {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "unidecode"
+version = "1.3.6"
+description = "ASCII transliterations of Unicode text"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "Unidecode-1.3.6-py3-none-any.whl", hash = "sha256:547d7c479e4f377b430dd91ac1275d593308dce0fc464fb2ab7d41f82ec653be"},
+ {file = "Unidecode-1.3.6.tar.gz", hash = "sha256:fed09cf0be8cf415b391642c2a5addfc72194407caee4f98719e40ec2a72b830"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "uritemplate"
+version = "4.1.1"
+description = "Implementation of RFC 6570 URI Templates"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"},
+ {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "urllib3"
+version = "2.0.4"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"},
+ {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"},
+]
+
+[package.extras]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
+socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
+zstd = ["zstandard (>=0.18.0)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "werkzeug"
+version = "2.3.7"
+description = "The comprehensive WSGI web application library."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "werkzeug-2.3.7-py3-none-any.whl", hash = "sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528"},
+ {file = "werkzeug-2.3.7.tar.gz", hash = "sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.1.1"
+
+[package.extras]
+watchdog = ["watchdog (>=2.3)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "wheel"
+version = "0.41.1"
+description = "A built-package format for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "wheel-0.41.1-py3-none-any.whl", hash = "sha256:473219bd4cbedc62cea0cb309089b593e47c15c4a2531015f94e4e3b9a0f6981"},
+ {file = "wheel-0.41.1.tar.gz", hash = "sha256:12b911f083e876e10c595779709f8a88a59f45aacc646492a67fe9ef796c1b47"},
+]
+
+[package.extras]
+test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "yapf"
+version = "0.40.1"
+description = "A formatter for Python code."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "yapf-0.40.1-py3-none-any.whl", hash = "sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"},
+ {file = "yapf-0.40.1.tar.gz", hash = "sha256:958587eb5c8ec6c860119a9c25d02addf30a44f75aa152a4220d30e56a98037c"},
+]
+
+[package.dependencies]
+importlib-metadata = ">=6.6.0"
+platformdirs = ">=3.5.1"
+tomli = ">=2.0.1"
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[[package]]
+name = "zipp"
+version = "3.16.2"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"},
+ {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"},
+]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
+
+[package.source]
+type = "legacy"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+reference = "BFSU"
+
+[metadata]
+lock-version = "2.0"
+python-versions = ">=3.10,<3.12"
+content-hash = "c2342781ffd073c0b3da69a61c6691b3acdb009ae6fa9c86504b75767d9b8207"
diff --git a/Yunzai/plugins/TRSS-Plugin/pyproject.toml b/Yunzai/plugins/TRSS-Plugin/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..71bc6528946da434c5bf99402613ec2e42d38e7b
--- /dev/null
+++ b/Yunzai/plugins/TRSS-Plugin/pyproject.toml
@@ -0,0 +1,37 @@
+[tool.poetry]
+name = "TRSS-Plugin"
+version = "1.0.0"
+description = "TRSS Yunzai Plugin"
+authors = ["时雨🌌星空 "]
+
+[tool.poetry.dependencies]
+python = ">=3.10,<3.12"
+matplotlib = "^3.7.2"
+torch = "^2.0.1"
+scipy = "^1.11.1"
+librosa = "^0.10.0.post2"
+unidecode = "^1.3.6"
+phonemizer = "^3.2.1"
+pypinyin = "^0.49.0"
+pypinyin-dict = "^0.6.0"
+jieba = "^0.42.1"
+cython = "^3.0.0"
+basicsr = "^1.4.2"
+facexlib = "^0.3.0"
+gfpgan = "^1.3.8"
+numpy = "^1.24.4"
+opencv-python = "^4.8.0.74"
+pillow = "^10.0.0"
+torchvision = "^0.15.2"
+tqdm = "^4.65.0"
+flask = "^2.3.2"
+rembg = "^2.0.50"
+cn2an = "^0.5.20"
+openjtalk = { version = "^0.3.0.dev3", markers = "platform_machine == 'x86_64'" }
+llvmlite = "^0.40.1"
+ruamel-yaml = "^0.17.32"
+
+[[tool.poetry.source]]
+name = "BFSU"
+url = "https://mirrors.bfsu.edu.cn/pypi/web/simple"
+priority = "default"
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/.all-contributorsrc b/Yunzai/plugins/yenai-plugin/.all-contributorsrc
new file mode 100644
index 0000000000000000000000000000000000000000..f95ca0a8e3678c70fab80256c151d83557727ca1
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.all-contributorsrc
@@ -0,0 +1,98 @@
+{
+ "projectName": "yenai-plugin",
+ "projectOwner": "yeyang52",
+ "repoType": "github",
+ "repoHost": "https://github.com",
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "commitConvention": "none",
+ "contributors": [
+ {
+ "login": "TimeRainStarSky",
+ "name": "时雨◎星空",
+ "avatar_url": "https://avatars.githubusercontent.com/u/63490117?v=4",
+ "profile": "https://github.com/TimeRainStarSky",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "Saury-loser",
+ "name": "花海里的秋刀鱼",
+ "avatar_url": "https://avatars.githubusercontent.com/u/106982493?v=4",
+ "profile": "https://github.com/Saury-loser",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "Georgebillion",
+ "name": "Georgebillion",
+ "avatar_url": "https://avatars.githubusercontent.com/u/40432824?v=4",
+ "profile": "https://github.com/Georgebillion",
+ "contributions": [
+ "ideas"
+ ]
+ },
+ {
+ "login": "xfdown",
+ "name": "小飞",
+ "avatar_url": "https://avatars.githubusercontent.com/u/42599406?v=4",
+ "profile": "https://github.com/xfdown",
+ "contributions": [
+ "ideas"
+ ]
+ },
+ {
+ "login": "liuzj288",
+ "name": "liuzj288",
+ "avatar_url": "https://avatars.githubusercontent.com/u/13833404?v=4",
+ "profile": "https://github.com/liuzj288",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "OKKOM2020",
+ "name": "OKKOM2020",
+ "avatar_url": "https://avatars.githubusercontent.com/u/88592811?v=4",
+ "profile": "https://github.com/OKKOM2020",
+ "contributions": [
+ "doc"
+ ]
+ },
+ {
+ "login": "kmiit",
+ "name": "大可鸭",
+ "avatar_url": "https://avatars.githubusercontent.com/u/61952405?v=4",
+ "profile": "https://github.com/kmiit",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "SmallK111407",
+ "name": "SunRyK",
+ "avatar_url": "https://avatars.githubusercontent.com/u/108290923?v=4",
+ "profile": "https://github.com/SmallK111407",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "ikechan8370",
+ "name": "ikechan8370",
+ "avatar_url": "https://avatars.githubusercontent.com/u/21212372?v=4",
+ "profile": "https://github.com/ikechan8370",
+ "contributions": [
+ "code"
+ ]
+ }
+ ],
+ "contributorsPerLine": 7,
+ "skipCi": true,
+ "linkToUsage": false
+}
diff --git a/Yunzai/plugins/yenai-plugin/.eslintrc.cjs b/Yunzai/plugins/yenai-plugin/.eslintrc.cjs
new file mode 100644
index 0000000000000000000000000000000000000000..36a4067b135e9d47650600b52d480c208574cee5
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.eslintrc.cjs
@@ -0,0 +1,26 @@
+module.exports = {
+ env: {
+ es2021: true,
+ node: true
+ },
+ extends: ['standard'],
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module'
+ },
+ globals: {
+ Bot: true,
+ redis: true,
+ logger: true,
+ plugin: true,
+ segment: true
+ },
+ rules: {
+ 'eqeqeq': ['off'],
+ 'prefer-const': ['off'],
+ 'arrow-body-style': 'off',
+ 'camelcase': 'off',
+ 'quote-props': ['error', 'consistent'],
+ 'no-eval': ['error', { 'allowIndirect': true }]
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/bug_report.md b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000000000000000000000000000000000..0be8127b0b9776ceff6239767d8dd31651b83726
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,35 @@
+---
+name: Bug 报告
+about: 创建一份报告来帮助我们改进
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**问题描述**
+请简要描述您遇到的问题。
+
+**Yunzai版本**
+Miao-Yunzai
+
+**如何复现**
+请详细描述如何复现问题,步骤越详细越好。
+
+1. 打开 '...'
+2. 点击 '....'
+3. 滚动到 '....'
+4. 出现错误
+
+**期望结果**
+请简要描述您期望得到的结果。
+
+**实际结果**
+请简要描述您实际得到的结果。
+
+**截图**
+如果可以,请提供相关截图以帮助解释您的问题。
+
+**其他说明**
+如果您有任何其他信息或说明,请在这里添加。
+
diff --git a/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/docs_feedback.md b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/docs_feedback.md
new file mode 100644
index 0000000000000000000000000000000000000000..f224f813856ed5f81ce129cc3e1c7e536690d18b
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/docs_feedback.md
@@ -0,0 +1,17 @@
+---
+name: 文档反馈
+about: 提供对文档的反馈和建议
+title: ''
+labels: documentation
+assignees: ''
+
+---
+
+**文档位置**
+请指明文档位置(链接、文件名等)。
+
+**反馈内容**
+请简要描述您对文档的反馈和建议。
+
+**其他说明**
+如果您有任何其他信息或说明,请在这里添加。
diff --git a/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/feature_request.md b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000000000000000000000000000000000..83d6cabccf101ab4e8c938e2f7ddd0d48c7abf5b
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: 功能建议
+about: 提出一个新功能的建议
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**问题描述**
+请简要描述您想要的新功能。
+
+**实现方式**
+请简要描述您希望实现这个新功能的方式。
+
+**当前的问题**
+如果没有这个新功能,您当前面临的问题是什么?
+
+**其他说明**
+如果您有任何其他信息或说明,请在这里添加。
diff --git a/Yunzai/plugins/yenai-plugin/.gitignore b/Yunzai/plugins/yenai-plugin/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1c5648e076ce7f28936631f2cee6979a0fc488fd
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/.gitignore
@@ -0,0 +1,9 @@
+node_modules/
+data/
+*_test.js
+test.*
+*.log
+.vscode/
+.eslintignore
+temp/
+*.css.map
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/CHANGELOG.md b/Yunzai/plugins/yenai-plugin/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..c4304db766c6996e23e635bc7f78ea262aefad28
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/CHANGELOG.md
@@ -0,0 +1,153 @@
+# 1.3.0
+
+* `赞我`可通过`超我`触发
+ * `赞他`同理
+ * **优化了**`赞他`的逻辑
+* 新增`#拉黑` `#取消拉黑`
+ * 可 **@** 一个人或直接写入QQ
+ * 可在拉黑后面加 **群** 来拉黑群聊
+* 将`#状态pro`的头像统一对齐显示
+* `加精`可通过`设精`触发
+* `#状态pro`显示所有Bot(**TRSS-Yunzai**)
+
+# 1.2.9
+
+* 优化**通知消息**及**事件**
+* `#状态`显示登录平台版本
+* 增加`赞他`命令ⁿᵉʷ
+
+# 1.2.8
+
+* 增加状态配置文件`config/state.yaml`
+* 增加网址测试超时时间配置
+* 增加网址测试配置
+* 将`whole.yaml`状态相关配置移入`state.yaml`
+* 优化状态异步任务使用`Promise.all`
+* 增加`移精`命令ⁿᵉʷ
+
+# 1.2.7
+
+* 删除依赖`puppeteer-extra``puppeteer-extra-plugin-stealth`
+* 并使用Puppeteer新无头模式,如**Chrome版本过低**可能无法使用
+
+
+# 1.2.1 ~ 1.2.6
+
+* 新增`jimp`依赖用于生成点赞回复图片
+* 新增`#设置机型`ⁿᵉʷ
+* 违禁词增加正则类型
+ * 示例:`#新增正则违禁词/🐔>🏀/`
+* 新增`#椰奶监控`ⁿᵉʷ
+* 新增`#(制服|写真|cos|正片|场照)acg`ⁿᵉʷ
+* 修改**搜图搜番**正则防止误触发
+* 删除`申请头衔`文案
+* 修改部分文案
+* 优化群违禁词匹配,增加违禁词添加人、添加时间
+* 优化群字符列表,字符id显示
+* 新增可选依赖项`puppeteer-extra``puppeteer-extra-plugin-stealth`
+* 更新Puppeteer 请求 ascii2d 绕过 cf js challenge
+* 新增`#加精`
+* 新增群违禁词功能
+
+# 1.2.0
+
+* 适配`Trss-Yunzai`一些功能
+* 修改`状态`布局
+* 新增**SauceNAO失败是否自动使用ascii2d**配置项
+* 新增**saucenao相似度过低是否自动使用ascii2d**配置项
+* 修改SauceNAO超时时间防止timeOut
+* `手表协议不支持点赞`不再发送,而是输出在控制台
+* 修复批量踢人报错
+* `椰奶状态`新增图表
+* 新增由 **@卡丘** 提供的bgg搜索
+* 新增`#椰奶设置xxx单独开启/关闭`ⁿᵉʷ
+ * 在群里发送该指令可单独开启或关闭功能
+* 新增`#椰奶设置xxx单独取消`ⁿᵉʷ
+ * 可以取消单独设置的功能
+* 椰奶设置图片检测到有单独设置的功能增加`群单独`标签
+* 新增**匿名**发送消息
+* 新增`对方正在输入`事件通知
+* 新增`#椰奶涩涩帮助`ⁿᵉʷ
+* 新增`#来点秀人`ⁿᵉʷ
+* 新增`#椰奶涩涩设置`ⁿᵉʷ
+* 新增`椰奶设置渲染精度`ⁿᵉʷ
+* 优化`椰奶帮助`样式
+* 修改点赞图片api
+* 新增`#查看代理设置`ⁿᵉʷ
+* 优化pixiv和bika开启或关闭图片直连
+* 优化回复撤回是文件时删除文件
+* 适配`segment`全局变量
+* 参考面板和收益曲线增加更新功能
+ * 例:`#更新甘雨参考面板`
+* 新增`#哔咔下一话`ⁿᵉʷ
+* 增加`Pixiv token登录`**墙内需代理**ⁿᵉʷ
+* 增加`#pixiv登录信息`查询登录状态ⁿᵉʷ
+* 增加`#来n张推荐图`ⁿᵉʷ
+ * 需登录账号,发送pixiv推荐图片
+* 增加`#哔咔下一页`ⁿᵉʷ
+ * 使用`#哔咔id`后快速查看下一页
+
+# 1.1.0
+
+* 增加`SauceNAO``Ascii2D`以图搜图ⁿᵉʷ
+* 增加`WhatAnime`以图搜番ⁿᵉʷ
+* 增加`#哔咔看[1~20]`搜索后快速查看指定作品ⁿᵉʷ
+* 分离哔咔id和作品信息方便复制id
+* 增加`pixiv``bika``搜图`更多配置项
+ * 请在**yenai-plugin/config/config/*.yaml**进行详情配置
+ * 如配置文件不是最新请复制**default_config**的文件到**config**进行配置
+* 优化目录结构
+* 新增`哔咔`相关功能ⁿᵉʷ
+* 支持配置哔咔和pixv代理
+* 支持哔咔和pixiv图片直连
+* 添加`#user搜索`pixiv用户搜索ⁿᵉʷ
+* 增加依赖`systeminformation`不安装将无法使用椰奶状态
+* 修改全部QQ接口为QQ官方接口,修改唱歌和翻译接口
+* 修改点赞图片接口
+* 增加**谁是龙王**和**发言榜单**发送官方页面图片
+* 增加`#来点神秘图`功能ⁿᵉʷ
+* 增加`#椰奶设置状态任务(开启|关闭)`ⁿᵉʷ
+ * 如出现许多cmd任务进程可尝试关闭此设置
+* 优化椰奶状态样式
+* 状态增加网速显示
+* 增加`#椰奶状态pro`感谢**@时雨星空**提供
+* 状态增加**NVIDIA**GPU显示
+* 增加`#群发言榜单`查看发言数据
+ * 可在后面加上7天查看7天的发言数据
+* 状态增加**Liunx**和**Mac**硬盘传输速率显示
+* 陌生人点赞设置并入椰奶设置
+* 增加陌生人点赞,感谢**@小飞**提供的方法
+ * 因不活跃的号可能会点赞失败请使用`#椰奶设置陌生人点赞开启`选择性开启
+* 增加`#相关作品+pid`查看某个的作品的相关作品
+* 增加`#发通知`艾特全体发送一条消息
+* 增加`#有内鬼`指令
+* Pid搜图增加更多信息
+* **sese**和**sesepro**支持群聊单独设置
+* 增加头衔屏蔽词
+* 增加群管功能
+ * 使用`#椰奶群管帮助`查看
+* 状态增加**windows**的硬盘内存显示
+* 删除功能`#waifu`
+* 增加Pixiv排行榜类型**AI、新人、原创...**
+* 增加好友申请方式更改`#更改好友申请方式``#(开启|关闭)好友添加`
+* 增加`#看看日|周|月|男性向|女性向榜`Pixiv榜单
+* 增加`#pid搜图`以Pixiv插画Id搜图
+* 增加`#tag搜图`以tag关键词搜图
+* 增加`#coser`
+* 增加`#waifu`
+* 增加`#查看热门tag`
+* 增加`#uid搜图`用画师的**uid**或**画师名**进行搜索
+* 增加`#同意|拒绝全部好友申请`
+* 增加`#半次元话题`
+* 增加`GitHub简略图`**当发送GitHub链接时会自动发送一张简略图**
+* 增加`#群星级`
+* 增加`#椰奶状态`**图片版状态**
+* 增加`#翻译`**有道翻译**
+* 增加`#搜索菜单`**使用各大引擎搜索返回图片**
+* 支持群通知可单独设置
+ * 请在**yenai-plugin/config/config/group.yaml**进行配置
+* 增加`#椰奶帮助`
+* 增加`#椰奶版本`
+* 增加`#椰奶更新日志`
+* 增加`#椰奶设置`
+
diff --git a/Yunzai/plugins/yenai-plugin/LICENSE b/Yunzai/plugins/yenai-plugin/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..94a9ed024d3859793618152ea559a168bbcbb5e2
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/Yunzai/plugins/yenai-plugin/README.md b/Yunzai/plugins/yenai-plugin/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ffbb548e7ac02587925f54d871d90f9f1bd78877
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/README.md
@@ -0,0 +1,285 @@
+
+
+
+
+
+# Yenai-Plugin
+
+🐑 **_Yenai-Plugin是一个Yunzai-Bot的扩展插件,提供对Bot的一些便捷操作。_**

+
+

+
+
+
+
+[](https://github.com/yeyang52/yenai-plugin/actions/workflows/deploy-docs.yml)
+[](https://vercel.com/yeyang52/yenai-plugin)
+[](https://app.netlify.com/sites/yenai-plugin/deploys)
+
+
+
+[](https://github.com/yeyang52/yenai-plugin/blob/master/LICENSE)
+[](https://gitee.com/Le-niao/Yunzai-Bot)
+[](https://jq.qq.com/?_wv=1027&k=o8FTig5Z)
+
+
+
+
+[](https://github.com/yeyang52/yenai-plugin/stargazers)
+[](https://github.com/yeyang52/yenai-plugin/network)
+[](https://github.com/yeyang52/yenai-plugin/issues)
+
+
+
+
+[](https://seladb.github.io/StarTrack-js/#/preload?r=yeyang52,yenai-plugin)
+
+
+
+---
+
+## 安装教程 💡
+
+请将Yenai-Plugin放置在Yunzai-Bot的plugins目录下,重启Yunzai-Bot后即可使用。
+
+1. 推荐使用git进行安装,以方便后续升级。在Yunzai目录打开终端,运行
+
+```
+// 使用github
+git clone --depth=1 https://github.com/yeyang52/yenai-plugin.git ./plugins/yenai-plugin
+
+// 使用gitee(可能更新不及时)
+git clone --depth=1 https://gitee.com/yeyang52/yenai-plugin.git ./plugins/yenai-plugin
+```
+
+2. 安装依赖(可选:不安装依赖将无法使用一些功能)
+
+```
+pnpm install
+```
+
+## 功能介绍 📖
+
+> Yenai-Plugin为您提供以下功能
+>
+> Tip:以下只是简单描述功能具体指令请使用 **#椰奶帮助 #椰奶群管帮助 #椰奶设置**查看
+
+
+ 事件通知
+
+- [x] ~~闪照监听~~ (目前企鹅闪照功能被ban)
+
+- [x] 撤回监听
+
+- [x] 好友申请
+
+- [x] 群邀请
+
+- [x] 好友|群 列表变动
+
+- [x] 好友|群 消息
+
+- [x] Bot被禁言
+
+Tip:具体可使用 **#椰奶设置** 查看
+
+
+
+ 助手功能
+
+- [x] 发送 群聊|好友 消息
+
+- [x] 改头像 | 改昵称 | 改状态 | 改昵称 | 改签名 | 改性别
+
+- [x] 删好友 | 退群
+
+- [x] 获取 好友|群 列表
+
+- [x] 增 删 查 说说
+
+- [x] 开启/关闭戳一戳
+
+
+
+
+ 事件处理
+
+- [x] 同意|拒绝 好友申请
+
+- [x] 同意|拒绝 群邀请
+
+- [x] 回复好友消息
+
+- [x] 查看现有好友申请/群邀请
+
+- [x] 同意/拒绝全部好友申请/群邀请
+
+- [x] 查看全部请求
+
+- [ ] 查看/回添 单向好友
+
+
+
+
+ 娱乐功能
+
+- [x] 随机唱鸭
+
+- [x] 角色收益曲线
+
+- [x] 赞我(支持陌生人点赞)
+
+- [x] coser
+
+- [x] 铃声搜索
+
+- [x] 支付宝到账语音
+
+- [x] 半次元话题
+
+- [x] 哪个叼毛是龙王
+
+
+
+ Pixiv功能
+
+- [x] Pixiv排行榜
+
+- [x] Tag搜图
+
+- [x] Pid搜图
+
+- [x] Uid搜图
+
+- [x] 查看热门Tag
+
+- [x] 查看相关作品
+
+Tip:详情请参考[此教程](https://docs.qq.com/doc/p/108e5d788607d988ac62e1512552c8bd2d870321)
+
+
+
+
+ 群管功能
+
+- [x] (全体)?禁言|解禁
+
+- [x] 允许|禁止 匿名
+
+- [x] 踢@群员
+
+- [x] 设置|取消 管理
+
+- [x] 增 删 查 公告
+
+- [x] 我要自闭
+
+- [x] 申请头衔
+
+- [x] 修改头衔
+
+- [x] 头衔屏蔽词
+
+- [x] 查看/清理多久没发言的人
+
+- [x] 查看/清理从未发言的人
+
+- [x] 查看最近入群情况
+
+- [x] 获取禁言列表
+
+- [x] 解除全部禁言
+
+- [x] 加群申请处理
+
+- [ ] 黑名单/白名单
+
+Tip:具体可使用 **#椰奶群管帮助** 查看
+
+
+
+ 搜图搜番
+
+- [x] [saucenao](https://saucenao.com)
+- [x] [whatanime](https://trace.moe)
+- [x] [ascii2d](https://ascii2d.net)
+
+
+
+
+
+ 图片状态
+
+
+
+
+
+
+更多信息请移步[文档](https://www.yenai.ren)
+
+## 特别鸣谢 ❤️
+
+- [Yunzai-Bot](https://gitee.com/Le-niao/Yunzai-Bot)
+- [cq-picsearcher-bot](https://github.com/Tsuk1ko/cq-picsearcher-bot)
+- [nonebot-plugin-picstatus](https://github.com/lgc2333/nonebot-plugin-picstatus)
+- [HibiAPI](https://github.com/mixmoe/HibiAPI)
+- [SauceNAO](https://saucenao.com/)
+- [Ascii2D](https://ascii2d.net/)
+- [trace.moe](https://trace.moe) ([GitHub](https://github.com/soruly/trace.moe))
+- [vilipix](https://www.vilipix.com/)
+
+### 贡献者 ✨
+
+
+[](#contributors-)
+
+感谢这些了不起的人 ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+
+
+
+
+
+
+
+
+
+
+本段遵循 [all-contributors](https://github.com/all-contributors/all-contributors) 规范,欢迎任何形式的贡献!
+
+## 友情链接 😊
+
+- [Yunzai-Bot插件索引](https://gitee.com/Hikari666/Yunzai-Bot-plugins-index)
+- [码云镜像库](https://gitee.com/yeyang52/yenai-plugin)
+- [Miao-Yunzai](https://gitee.com/yoimiya-kokomi/Miao-Yunzai)
+
+## 免责声明 ❗
+
+1. 功能仅限内部交流与小范围使用,请勿将Yunzai-Bot及Yenai-Plugin用于任何以盈利为目的的场景.
+2. 图片与其他素材均来自于网络,仅供交流学习使用,如有侵权请联系,会立即删除.
+
+## 联系方式
+
+🐧:746659424
+
+💬:254974507(已锁)
+
+❤️:[打赏](https://www.yenai.ren/donate.html)
+
+
diff --git a/Yunzai/plugins/yenai-plugin/apps/admin.js b/Yunzai/plugins/yenai-plugin/apps/admin.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c74fc3b641362eebdf4457802c6fd8c3796938a
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/admin.js
@@ -0,0 +1,264 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import fs from 'fs'
+import _ from 'lodash'
+import { Config } from '../components/index.js'
+import { setu, puppeteer } from '../model/index.js'
+
+/** 设置项 */
+const OtherCfgType = {
+ 全部通知: 'notificationsAll',
+ 状态: 'state',
+ 陌生人点赞: 'Strangers_love'
+}
+const SeSeCfgType = {
+ 涩涩: 'sese',
+ 涩涩pro: 'sesepro',
+ 匿名: 'anonymous',
+ 代理: {
+ name: 'proxy',
+ key: 'switchProxy'
+ }
+}
+const NoticeCfgType = {
+ 好友消息: 'privateMessage',
+ 群消息: 'groupMessage',
+ 群临时消息: 'grouptemporaryMessage',
+ 群撤回: 'groupRecall',
+ 好友撤回: 'PrivateRecall',
+ // 申请通知
+ 好友申请: 'friendRequest',
+ 群邀请: 'groupInviteRequest',
+ 加群申请: 'addGroupApplication',
+ // 信息变动
+ 群管理变动: 'groupAdminChange',
+ // 列表变动
+ 好友列表变动: 'friendNumberChange',
+ 群聊列表变动: 'groupNumberChange',
+ 群成员变动: 'groupMemberNumberChange',
+ // 其他通知
+ 闪照: 'flashPhoto',
+ 禁言: 'botBeenBanned',
+ 输入: 'input'
+}
+/** 分开开关和数字 */
+const SwitchCfgType = {
+ ...NoticeCfgType, ...OtherCfgType, ...SeSeCfgType
+}
+const NumberCfgType = {
+ 渲染精度: {
+ key: 'renderScale',
+ limit: '50-200'
+ },
+ 删除缓存时间: {
+ key: 'deltime',
+ limit: '>120'
+ }
+}
+
+/** 支持单独设置的项 */
+const aloneKeys = [
+ '群消息', '群临时消息', '群撤回', '群邀请', '群管理变动', '群聊列表变动', '群成员变动', '加群通知', '禁言', '闪照', '匿名', '涩涩', '涩涩pro'
+]
+
+const SwitchCfgReg = new RegExp(`^#椰奶设置(${Object.keys(SwitchCfgType).join('|')})(单独)?(开启|关闭|取消)$`)
+const NumberCfgReg = new RegExp(`^#椰奶设置(${Object.keys(NumberCfgType).join('|')})(\\d+)秒?$`)
+
+export class Admin extends plugin {
+ constructor () {
+ super({
+ name: '椰奶配置',
+ event: 'message',
+ priority: 100,
+ rule: [
+ {
+ reg: SwitchCfgReg,
+ fnc: 'ConfigSwitch'
+ },
+ {
+ reg: NumberCfgReg,
+ fnc: 'ConfigNumber'
+ },
+ {
+ reg: '^#椰奶(sese|涩涩)?设置$',
+ fnc: 'Settings'
+ },
+ {
+ reg: '^#椰奶(启用|禁用)全部通知$',
+ fnc: 'SetAllNotice'
+ }
+ ]
+ })
+ }
+
+ // 更改配置
+ async ConfigSwitch (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return false }
+ // 解析消息
+ let regRet = SwitchCfgReg.exec(e.msg)
+ let key = regRet[1]
+ let is = regRet[3] == '开启'
+ if (!e.group_id && regRet[2]) {
+ return e.reply('❎ 请在要单独设置的群聊发送单独设置命令')
+ }
+ if (!aloneKeys.includes(key) && regRet[2]) {
+ return e.reply('❎ 该设置项不支持单独设置')
+ }
+
+ // 单独设置
+ if (regRet[2]) {
+ let isdel = regRet[3] == '取消'
+ Config.aloneModify(e.group_id, SwitchCfgType[key], is, isdel)
+ } else {
+ let _key = SwitchCfgType[key]
+ Config.modify(_key?.name ?? 'whole', _key?.key ?? _key, is)
+
+ // 单独处理
+ if (key == '涩涩pro' && is) Config.modify('whole', 'sese', is)
+ if (key == '涩涩' && !is) Config.modify('whole', 'sesepro', is)
+ }
+ // 渲染图片
+ if (Object.keys(SeSeCfgType).includes(key)) {
+ this.SeSe_Settings(e)
+ } else {
+ this.index_Settings(e)
+ }
+ }
+
+ // 修改数字设置
+ async ConfigNumber (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return false }
+ let regRet = e.msg.match(NumberCfgReg)
+ let type = NumberCfgType[regRet[1]]
+ let number = checkNumberValue(regRet[2], type.limit)
+ Config.modify(type.name ?? 'whole', type.key, number)
+ this.index_Settings(e)
+ }
+
+ // 修改全部通知设置
+ async SetAllNotice (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return false }
+ let yes = /启用/.test(e.msg)
+ for (let i in NoticeCfgType) {
+ Config.modify('whole', NoticeCfgType[i], yes)
+ }
+ this.index_Settings(e)
+ }
+
+ async Settings (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return false }
+ if (/sese|涩涩/.test(e.msg)) {
+ this.SeSe_Settings(e)
+ } else {
+ this.index_Settings(e)
+ }
+ }
+
+ // 渲染发送图片
+ async index_Settings (e) {
+ let data = {}
+ const special = ['deltime', 'renderScale']
+ let _cfg = Config.getGroup(e.group_id)
+ for (let key in _cfg) {
+ if (special.includes(key)) {
+ data[key] = Number(Config.whole[key])
+ } else {
+ let groupCfg = Config.getConfig('group')[e.group_id]
+ let isAlone = groupCfg ? groupCfg[key] : undefined
+ data[key] = getStatus(_cfg[key], isAlone)
+ }
+ }
+ // 渲染图像
+ return await puppeteer.render('admin/index', {
+ ...data,
+ bg: await rodom()
+ }, {
+ e,
+ scale: 1.4
+ })
+ }
+
+ // 查看涩涩设置
+ async SeSe_Settings (e) {
+ let set = setu.getSeSeConfig(e)
+ let { proxy, pixiv, bika } = Config
+ let { sese, sesepro, anonymous } = Config.getGroup(e.group_id)
+ let { sese: _sese, sesepro: _sesepro, anonymous: _anonymous } = Config.getConfig('group')[e.group_id] ?? {}
+ let data = {
+ sese: getStatus(sese, _sese),
+ sesepro: getStatus(sesepro, _sesepro),
+ anonymous: getStatus(anonymous, _anonymous),
+ r18: getStatus(set.r18),
+ cd: Number(set.cd),
+ recall: set.recall ? set.recall : '无',
+ switchProxy: getStatus(proxy.switchProxy),
+ pixivDirectConnection: getStatus(pixiv.pixivDirectConnection),
+ bikaDirectConnection: getStatus(bika.bikaDirectConnection),
+ pixivImageProxy: pixiv.pixivImageProxy,
+ bikaImageProxy: bika.bikaImageProxy,
+ imageQuality: bika.imageQuality
+ }
+ // 渲染图像
+ return await puppeteer.render('admin/sese', {
+ ...data,
+ bg: await rodom()
+ }, {
+ e,
+ scale: 1.4
+ })
+ }
+}
+
+// 随机底图
+const rodom = async function () {
+ let image = fs.readdirSync('./plugins/yenai-plugin/resources/admin/imgs/bg')
+ let listImg = []
+ for (let val of image) {
+ listImg.push(val)
+ }
+ let imgs = listImg.length == 1 ? listImg[0] : listImg[_.random(0, listImg.length - 1)]
+ return imgs
+}
+
+const getStatus = function (rote, alone) {
+ let badge = alone != undefined ? '群单独' : ''
+ if (rote) {
+ return badge + '已开启
'
+ } else {
+ return badge + '已关闭
'
+ }
+}
+
+/**
+ * 检查一个数值是否满足给定的限制条件,并返回经过验证的数值。
+ *
+ * @param {number} value - 要检查的数值。
+ * @param {string} limit - 要检查的限制条件。
+ * 限制条件可以是以下格式之一:
+ * - "X-Y" 形式的范围限制条件,其中 X 和 Y 是表示下限和上限的数字。
+ * - "X" 形式的比较限制条件,其中 X 是表示限制值的数字。
+ * @returns {number} 经过验证的数值。如果给定的值超出了限制条件,则返回限制条件对应的最大值或最小值,否则返回原值。
+ */
+function checkNumberValue (value, limit) {
+ // 检查是否存在限制条件
+ if (!limit) {
+ return value
+ }
+ // 解析限制条件
+ const [symbol, limitValue] = limit.match(/^([<>])?(.+)$/).slice(1)
+ const parsedLimitValue = parseFloat(limitValue)
+
+ // 检查比较限制条件
+ if ((symbol === '<' && value > parsedLimitValue) || (symbol === '>' && value < parsedLimitValue)) {
+ return parsedLimitValue
+ }
+
+ // 检查范围限制条件
+ if (!isNaN(value)) {
+ const [lowerLimit, upperLimit] = limit.split('-').map(parseFloat)
+ const clampedValue = Math.min(Math.max(value, lowerLimit || -Infinity), upperLimit || Infinity)
+ return clampedValue
+ }
+
+ // 如果不符合以上任何条件,则返回原值
+ return parseFloat(value)
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/assistant.js b/Yunzai/plugins/yenai-plugin/apps/assistant.js
new file mode 100644
index 0000000000000000000000000000000000000000..524d921271fadf56111d10b123db235771ad2262
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/assistant.js
@@ -0,0 +1,952 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import { common, QQApi } from '../model/index.js'
+import { Version } from '../components/index.js'
+import _ from 'lodash'
+import moment from 'moment'
+import { status } from '../constants/other.js'
+import yaml from 'yaml'
+import fs from 'node:fs'
+/** API请求错误文案 */
+const API_ERROR = '❎ 出错辣,请稍后重试'
+
+// 命令正则
+let FriendsReg = /^#发好友\s?(\d+)\s?(.*)$/
+let GroupMsgReg = /^#发群聊\s?(\d+)\s?(.*)$/
+let GroupListMsgReg = /^#发群列表\s?(\d+(,\d+){0,})\s?(.*)$/
+let friendTypeReg = /^#更改好友申请方式([0123])((.*)\s(.*))?$/
+
+export class Assistant extends plugin {
+ constructor() {
+ super({
+ name: '椰奶小助手',
+ event: 'message',
+ priority: 2000,
+ rule: [
+ {
+ reg: '^#改头像',
+ fnc: 'SetAvatar'
+ },
+ {
+ reg: '^#改昵称',
+ fnc: 'SetNickname'
+ },
+ {
+ reg: '^#改签名',
+ fnc: 'SetSignature'
+ },
+ {
+ reg: '^#改状态',
+ fnc: 'SetOnlineStatus'
+ },
+ {
+ reg: FriendsReg, // 发好友
+ fnc: 'SendFriendMsg'
+ },
+ {
+ reg: GroupMsgReg, // 发群聊
+ fnc: 'SendGroupMsg'
+ },
+ {
+ reg: GroupListMsgReg, // 发群列表
+ fnc: 'SendGroupListMsg'
+ },
+ {
+ reg: '^#退群',
+ fnc: 'QuitGroup'
+ },
+ {
+ reg: '^#删好友',
+ fnc: 'DeleteFriend'
+ },
+ {
+ reg: '^#改性别',
+ fnc: 'SetGender'
+ },
+ {
+ reg: '^#取直链',
+ fnc: 'ImageLink'
+ },
+ {
+ reg: '^#取face',
+ fnc: 'Face'
+ },
+ {
+ reg: '^#获?取说说列表(\\d+)?$',
+ fnc: 'Qzonelist'
+ },
+ {
+ reg: '^#删说说(\\d+)$',
+ fnc: 'Qzonedel'
+ },
+ {
+ reg: '^#发说说',
+ fnc: 'Qzonesay'
+ },
+ {
+ reg: '^#(清空说说|清空留言)$',
+ fnc: 'QzonedelAll'
+ },
+ {
+ reg: '^#改群名片',
+ fnc: 'SetGroupCard'
+ },
+ {
+ reg: '^#改群头像',
+ fnc: 'SetGroupAvatar'
+ },
+ {
+ reg: '^#改群昵称',
+ fnc: 'SetGroupName'
+ },
+ {
+ reg: '^#获取(群|好友)列表$',
+ fnc: 'GlOrFl'
+ },
+ {
+ reg: '^#(开启|关闭)戳一戳$',
+ fnc: 'Cyc'
+ },
+ {
+ reg: '^#?撤回$',
+ fnc: 'RecallMsgown'
+ },
+ {
+ reg: '^#(开启|关闭)好友添加$',
+ fnc: 'FriendSwitch'
+ },
+ {
+ reg: friendTypeReg, // 更改好友申请方式
+ fnc: 'FriendType'
+ },
+ {
+ reg: '#设置机型.*', // 更改好友申请方式
+ fnc: 'setModel'
+ },
+ {
+ reg: '^#?拉黑(群|群聊)?',
+ fnc: 'BlockOne'
+ },
+ {
+ reg: '^#?(取消|删除|移除)(群|群聊)?拉黑(群|群聊)?',
+ fnc: 'CancelBlockOne'
+ }
+ ]
+ })
+ }
+
+ get Bot() {
+ return this.e.bot ?? Bot
+ }
+
+ /** 改头像 */
+ async SetAvatar(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ if (!e.img) {
+ this.setContext('_avatarContext')
+ e.reply('⚠ 请发送图片')
+ return
+ }
+
+ await this.Bot.setAvatar(e.img[0])
+ .then(() => { e.reply('✅ 头像修改成功') })
+ .catch((err) => {
+ e.reply('❎ 头像修改失败')
+ logger.error(err)
+ })
+ }
+
+ async _avatarContext() {
+ let img = this.e.img
+ if (/取消/.test(this.e.msg)) {
+ this.finish('_avatarContext')
+ await this.reply('✅ 已取消')
+ return
+ }
+ if (!img) {
+ this.setContext('_avatarContext')
+ await this.reply('⚠ 请发送图片或取消')
+ return
+ }
+ await (this.e.bot ?? Bot).setAvatar(img[0])
+ .then(() => this.e.reply('✅ 头像修改成功'))
+ .catch((err) => {
+ this.e.reply('❎ 头像修改失败')
+ logger.error(err)
+ })
+
+ this.finish('_avatarContext')
+ }
+
+ /** 改昵称 */
+ async SetNickname(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let name = e.msg.replace(/#|改昵称/g, '').trim()
+
+ await this.Bot.setNickname(name)
+ .then(() => e.reply('✅ 昵称修改成功'))
+ .catch((err) => {
+ e.reply('❎ 昵称修改失败')
+ logger.error(err)
+ })
+ }
+
+ /** 改群名片 */
+ async SetGroupCard(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let group = ''
+ let card = ''
+
+ if (e.isPrivate) {
+ let msg = e.msg.split(' ')
+
+ group = msg[1].match(/[1-9]\d*/g)
+
+ card = msg.slice(2).join(' ')
+
+ if (!group) return e.reply('❎ 群号不能为空')
+
+ if (!this.Bot.gl.get(Number(msg[1]))) return e.reply('❎ 群聊列表查无此群')
+ } else {
+ group = e.group_id
+ card = e.msg.replace(/#|改群名片/g, '').trim()
+ }
+
+ if (!card) {
+ return e.reply('❎ 名片不能为空')
+ }
+ this.Bot.pickGroup(group).setCard(this.Bot.uin, card)
+ .then(() => e.reply('✅ 群名片修改成功'))
+ .catch(err => {
+ e.reply('✅ 群名片修改失败')
+ logger.error(err)
+ })
+ }
+
+ /** 改群头像 */
+ async SetGroupAvatar(e) {
+ if (e.isPrivate) {
+ if (!e.isMaster) return logger.mark(`${e.logFnc}不为主人`)
+ e.group_id = e.msg.replace(/#|改群头像/g, '').trim()
+
+ if (!e.group_id) return e.reply('❎ 群号不能为空')
+
+ if (!(/^\d+$/.test(e.group_id))) return e.reply('❎ 您的群号不合法')
+
+ if (!this.Bot.gl.get(Number(e.group_id))) return e.reply('❎ 群聊列表查无此群')
+ e.group_id = Number(e.group_id)
+ } else if (!e.member.is_admin && !e.member.is_owner && !e.isMaster) {
+ return logger.mark(`${e.logFnc}该群员权限不足`)
+ }
+ let groupObj = this.Bot.pickGroup(e.group_id)
+ if (!groupObj.is_admin && !groupObj.is_owner) {
+ return e.reply('❎ 没有管理员人家做不到啦~>_<')
+ }
+ if (!e.img) {
+ this.setContext('_GroupAvatarContext')
+ e.reply('⚠ 请发送图片')
+ return
+ }
+
+ this.Bot.pickGroup(e.group_id).setAvatar(e.img[0])
+ .then(() => e.reply('✅ 群头像修改成功'))
+ .catch((err) => {
+ e.reply('✅ 群头像修改失败')
+ logger.error(err)
+ })
+ }
+
+ _GroupAvatarContext(e) {
+ let img = this.e.img
+ if (/取消/.test(this.e.msg)) {
+ this.finish('_GroupAvatarContext')
+ this.e.reply('✅ 已取消')
+ return
+ }
+ if (!img) {
+ this.setContext('_GroupAvatarContext')
+ this.e.reply('⚠ 请发送图片或取消')
+ return
+ }
+ this.Bot.pickGroup(e.group_id).setAvatar(this.e.img[0])
+ .then(() => this.e.reply('✅ 群头像修改成功'))
+ .catch((err) => {
+ this.e.reply('✅ 群头像修改失败')
+ logger.error(err)
+ })
+
+ this.finish('_GroupAvatarContext')
+ }
+
+ /** 改群昵称 */
+ async SetGroupName(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let group = ''
+ let card = ''
+
+ if (e.isPrivate) {
+ if (!e.isMaster) return
+
+ let msg = e.msg.split(' ')
+ group = msg[1].match(/[1-9]\d*/g)
+ card = msg.slice(2).join(' ')
+
+ if (!group) return e.reply('❎ 群号不能为空')
+ if (!this.Bot.gl.get(Number(msg[1]))) return e.reply('❎ 群聊列表查无此群')
+ } else {
+ if (!e.member.is_admin && !e.member.is_owner && !e.isMaster) return logger.mark(`${e.logFnc}该群员权限不足`)
+ group = e.group_id
+ card = e.msg.replace(/#|改群昵称/g, '').trim()
+ }
+
+ if (!card) return e.reply('❎ 昵称不能为空')
+
+ group = Number(group)
+
+ if (this.Bot.pickGroup(group).is_admin || this.Bot.pickGroup(group).is_owner) {
+ this.Bot.pickGroup(group).setName(card)
+ .then(() => e.reply('✅ 群昵称修改成功'))
+ .catch(err => {
+ e.reply('✅ 群昵称修改失败')
+ logger.error(err)
+ })
+ } else {
+ return e.reply('❎ 没有管理员人家做不到啦~>_<')
+ }
+ }
+
+ /** 改签名 */
+ async SetSignature(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let signs = e.msg.replace(/#|改签名/g, '').trim()
+ await this.Bot.setSignature(signs)
+ .then(() => e.reply('✅ 签名修改成功'))
+ .catch((err) => {
+ e.reply('❎ 签名修改失败')
+ logger.error(err)
+ })
+ }
+
+ /** 改状态 */
+ async SetOnlineStatus(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let signs = e.msg.replace(/#|改状态/g, '').trim()
+
+ if (!signs) return e.reply('❎ 状态不为空,可选值:我在线上,离开,隐身,忙碌,Q我吧,请勿打扰')
+
+ let statusMirr = _.invert(status)
+ if (!(signs in statusMirr)) return e.reply('❎ 可选值:我在线上,离开,隐身,忙碌,Q我吧,请勿打扰')
+
+ await this.Bot.setOnlineStatus(statusMirr[signs])
+ .then(() => e.reply(`✅ 现在的在线状态为【${status[this.Bot.status]}】`))
+ .catch(err => {
+ e.reply('❎ 在线状态修改失败')
+ logger.error(err)
+ })
+ return true
+ }
+
+ /** 发好友 */
+ async SendFriendMsg(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = FriendsReg.exec(e.msg)
+ let qq = regRet[1]
+ e.message[0].text = regRet[2]
+ if (!/^\d+$/.test(qq)) return e.reply('❎ QQ号不正确,人家做不到的啦>_<~')
+
+ if (!this.Bot.fl.get(Number(qq))) return e.reply('❎ 好友列表查无此人')
+
+ if (!e.message[0].text) e.message.shift()
+
+ if (e.message.length === 0) return e.reply('❎ 消息不能为空')
+
+ await this.Bot.pickFriend(qq).sendMsg(e.message)
+ .then(() => e.reply('✅ 私聊消息已送达'))
+ .catch(err => common.handleException(e, err, { MsgTemplate: '❎ 发送失败\n错误信息为:{error}' }))
+ }
+
+ /** 发群聊 */
+ async SendGroupMsg(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = GroupMsgReg.exec(e.msg)
+
+ let gpid = regRet[1]
+
+ e.message[0].text = regRet[2]
+
+ if (!e.message[0].text) e.message.shift()
+
+ if (e.message.length === 0) return e.reply('❎ 消息不能为空')
+
+ if (!/^\d+$/.test(gpid)) return e.reply('❎ 您输入的群号不合法')
+
+ if (!this.Bot.gl.get(Number(gpid))) return e.reply('❎ 群聊列表查无此群')
+
+ await this.Bot.pickGroup(gpid).sendMsg(e.message)
+ .then(() => e.reply('✅ 群聊消息已送达'))
+ .catch((err) => common.handleException(e, err, { MsgTemplate: '❎ 发送失败\n错误信息为:{error}' }))
+ }
+
+ // 发送群列表
+ async SendGroupListMsg(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ // 获取参数
+ let regRet = GroupListMsgReg.exec(e.msg)
+ let gpid = regRet[1]
+ e.message[0].text = regRet[3]
+
+ if (!e.message[0].text) e.message.shift()
+
+ if (e.message.length === 0) return e.reply('❎ 消息不能为空')
+
+ let groupidList = []
+ let sendList = []
+
+ // 获取群列表
+ let listMap = Array.from(this.Bot.gl.values())
+
+ listMap.forEach((item) => {
+ groupidList.push(item.group_id)
+ })
+
+ let groupids = gpid.split(',')
+
+ if (!groupids.every(item => item <= groupidList.length)) return e.reply('❎ 序号超过合法值!!!')
+
+ groupids.forEach((item) => {
+ sendList.push(groupidList[Number(item) - 1])
+ })
+
+ if (sendList.length > 3) return e.reply('❎ 不能同时发太多群聊,号寄概率增加!!!')
+
+ if (sendList.length === 1) {
+ await this.Bot.pickGroup(sendList[0]).sendMsg(e.message)
+ .then(() => e.reply('✅ ' + sendList[0] + ' 群聊消息已送达'))
+ .catch((err) =>
+ common.handleException(e, err, { MsgTemplate: `❎ ${sendList[0]} 发送失败\n错误信息为:{error}` })
+ )
+ } else {
+ e.reply('发送多个群聊,将每5秒发送一条消息!')
+ for (let i of sendList) {
+ await this.Bot.pickGroup(i).sendMsg(e.message)
+ .then(() => e.reply('✅ ' + i + ' 群聊消息已送达'))
+ .catch((err) =>
+ common.handleException(e, err, { MsgTemplate: `❎ ${i} 发送失败\n错误信息为:{error}` }))
+ await common.sleep(5000)
+ }
+ }
+ return false
+ }
+
+ /** 退群 */
+ async QuitGroup(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let quits = e.msg.replace(/#|退群/g, '').trim()
+
+ if (!quits) return e.reply('❎ 群号不能为空')
+
+ if (!/^\d+$/.test(quits)) return e.reply('❎ 群号不合法')
+
+ if (!this.Bot.gl.get(Number(quits))) return e.reply('❎ 群聊列表查无此群')
+
+ await this.Bot.pickGroup(quits).quit()
+ .then(() => e.reply('✅ 已退出群聊'))
+ .catch((err) => {
+ e.reply('❎ 退出失败')
+ logger.error(err)
+ })
+ }
+
+ /** 删好友 */
+ async DeleteFriend(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let quits = e.msg.replace(/#|删好友/g, '').trim()
+
+ if (e.message[1]) {
+ quits = e.message[1].qq
+ } else {
+ quits = quits.match(/[1-9]\d*/g)
+ }
+ if (!quits) return e.reply('❎ 请输入正确的QQ号')
+
+ if (!this.Bot.fl.get(Number(quits))) return e.reply('❎ 好友列表查无此人')
+
+ await this.Bot.pickFriend(quits).delete()
+ .then(() => e.reply('✅ 已删除好友'))
+ .catch((err) => {
+ e.reply('❎ 删除失败')
+ logger.error(err)
+ })
+ }
+
+ /** 改性别 */
+ async SetGender(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let sex = e.msg.replace(/#|改性别/g, '').trim()
+
+ if (!sex) return e.reply('❎ 性别不能为空 可选值:男,女,无\n(改为无,为无性别)')
+
+ let res = {
+ 无: 0,
+ 男: 1,
+ 女: 2
+ }
+ if (!(sex in res)) return e.reply('❎ 可选值:男,女,无(改为无,为无性别)')
+
+ await this.Bot.setGender(res[sex])
+ .then(() => e.reply('✅ 已修改性别'))
+ .catch((err) => {
+ e.reply('❎ 修改失败')
+ logger.error(err)
+ })
+ }
+
+ /** 取直链 */
+ async ImageLink(e) {
+ let img = []
+ if (e.source) {
+ let source
+ if (e.isGroup) {
+ source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ } else {
+ source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ }
+ for (let i of source.message) {
+ if (i.type == 'image') {
+ img.push(i.url)
+ }
+ }
+ } else {
+ img = e.img
+ }
+
+ if (_.isEmpty(img)) {
+ this.setContext('_ImageLinkContext')
+ await this.reply('⚠ 请发送图片')
+ return
+ }
+ await e.reply(`✅ 检测到${img.length}张图片`)
+ if (img.length >= 2) {
+ // 大于两张图片以转发消息发送
+ let msg = []
+ for (let i of img) {
+ msg.push([segment.image(i), '直链:', i])
+ }
+ common.getforwardMsg(e, msg)
+ } else {
+ await e.reply([segment.image(img[0]), '直链:', img[0]])
+ }
+ return true
+ }
+
+ async _ImageLinkContext() {
+ let img = this.e.img
+ if (this.e.msg === '取消') {
+ this.finish('_ImageLinkContext')
+ await this.reply('✅ 已取消')
+ return
+ }
+ if (!img) {
+ this.setContext('_ImageLinkContext')
+ await this.reply('⚠ 请发送图片或取消')
+ return
+ }
+ await this.e.reply(img[0])
+ this.finish('_ImageLinkContext')
+ }
+
+ /** 取Face表情 */
+ async Face(e) {
+ let face = []
+ for (let m of e.message) {
+ if (m.type === 'face') {
+ let s = false
+ for (let i of face) { if (i.id === m.id) s = true }
+ if (!s) face.push(m)
+ }
+ }
+ if (face.length === 0) return e.reply('❎ 表情参数不可为空', true)
+
+ let res = face.map(function (item) {
+ return [
+ '表情:',
+ item,
+ `\nid:${item.id}`,
+ `\n描述:${item.text}`
+ ]
+ })
+
+ if (res.length >= 2) {
+ common.getforwardMsg(e, res)
+ } else {
+ e.reply(res[0])
+ }
+ }
+
+ /** QQ空间 说说列表 */
+ async Qzonelist(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let page = e.msg.replace(/#|获?取说说列表/g, '').trim()
+ if (!page) {
+ page = 0
+ } else {
+ page = page - 1
+ }
+
+ // 获取说说列表
+ let list = await new QQApi(e).getQzone(5, page * 5)
+
+ if (!list) return e.reply(API_ERROR)
+ if (list.total == 0) return e.reply('✅ 说说列表为空')
+
+ let msg = [
+ '✅ 获取成功,说说列表如下:\n',
+ ...list.msglist.map((item, index) =>
+ `${page * 5 + index + 1}.${_.truncate(item.content, { length: 15 })}\n- [${item.secret ? '私密' : '公开'}] | ${moment(item.created_time * 1000).format('MM/DD HH:mm')} | ${item.commentlist?.length || 0}条评论\n`
+ ),
+ `页数:[${page + 1}/${Math.ceil(list.total / 5)}]`
+ ]
+ e.reply(msg)
+ }
+
+ /** 删除说说 */
+ async Qzonedel(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let pos = e.msg.match(/\d+/)
+ // 获取说说列表
+ let list = await new QQApi(e).getQzone(1, pos - 1)
+
+ if (!list) return e.reply(API_ERROR)
+ if (!list.msglist) return e.reply('❎ 未获取到该说说')
+
+ // 要删除的说说
+ let domain = list.msglist[0]
+ // 请求接口
+ let result = await new QQApi(e).delQzone(domain.tid, domain.t1_source)
+ if (!result) return e.reply(API_ERROR)
+ // debug
+ logger.debug(e.logFnc, result)
+
+ if (result.subcode != 0) e.reply('❎ 未知错误' + JSON.parse(result))
+ // 发送结果
+ e.reply(`✅ 删除说说成功:\n ${pos}.${_.truncate(domain.content, { length: 15 })} \n - [${domain.secret ? '私密' : '公开'}] | ${moment(domain.created_time * 1000).format('MM/DD HH:mm')} | ${domain.commentlist?.length || 0} 条评论`)
+ }
+
+ /** 发说说 */
+ async Qzonesay(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let con = e.msg.replace(/#|发说说/g, '').trim()
+ let result = await new QQApi(e).setQzone(con, e.img)
+ if (!result) return e.reply(API_ERROR)
+
+ if (result.code != 0) return e.reply(`❎ 说说发表失败\n${JSON.stringify(result)}`)
+
+ let msg = ['✅ 说说发表成功,内容:\n', _.truncate(result.content, { length: 15 })]
+ if (result.pic) {
+ msg.push(segment.image(result.pic[0].url1))
+ }
+ msg.push(`\n- [${result.secret ? '私密' : '公开'}] | ${moment(result.t1_ntime * 1000).format('MM/DD HH:mm')}`)
+ e.reply(msg)
+ }
+
+ /** 清空说说和留言 */
+ async QzonedelAll(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ if (/清空说说/.test(e.msg)) {
+ this.setContext('_QzonedelAllContext')
+ e.reply('✳️ 即将删除全部说说请发送:\n' + '------确认清空或取消------')
+ e.Qzonedetermine = true
+ } else if (/清空留言/.test(e.msg)) {
+ this.setContext('_QzonedelAllContext')
+ e.reply('✳️ 即将删除全部留言请发送:\n' + '------确认清空或取消------')
+ e.Qzonedetermine = false
+ }
+ }
+
+ async _QzonedelAllContext(e) {
+ let msg = this.e.msg
+ if (/#?确认清空/.test(msg)) {
+ this.finish('_QzonedelAllContext')
+ let result
+ if (e.Qzonedetermine) {
+ result = await new QQApi(this.e).delQzoneAll()
+ } else {
+ result = await new QQApi(this.e).delQzoneMsgbAll()
+ }
+
+ this.e.reply(result)
+ return true
+ } else if (/#?取消/.test(msg)) {
+ this.finish('_QzonedelAllContext')
+ this.e.reply('✅ 已取消')
+ return false
+ } else {
+ this.setContext('_QzonedelAllContext')
+ this.e.reply('❎ 请输入:确认清空或取消')
+ return false
+ }
+ }
+
+ // 获取群|好友列表
+ async GlOrFl(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let msg = []
+ if (/群列表/.test(e.msg)) {
+ // 获取群列表并转换为数组
+ let listMap = Array.from(this.Bot.gl.values())
+ msg = [
+ `群列表如下,共${listMap.length}个群`,
+ listMap.map((item, index) => `${index + 1}、${item.group_name}(${item.group_id})`).join('\n'),
+ '可使用 #退群123456789 来退出某群',
+ '可使用 #发群列表 <序号> <消息> 来快速发送消息,多个群聊请用 "," 分隔 不能大于3 容易寄'
+ ]
+ } else {
+ // 获取好友列表并转换为数组
+ let listMap = Array.from(this.Bot.fl.values())
+ msg = [
+ `好友列表如下,共${listMap.length}个好友`,
+ listMap.map((item, index) => `${index + 1}、${item.nickname}(${item.user_id})`).join('\n'),
+ '可使用 #删好友123456789 来删除某人'
+ ]
+ }
+
+ common.getforwardMsg(e, msg)
+ }
+
+ // 引用撤回
+ async RecallMsgown(e) {
+ if (!e.source) return false
+ let source
+ if (e.isGroup) {
+ source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ } else {
+ source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ }
+ let target = e.isGroup ? e.group : e.friend
+
+ if (source.sender.user_id != this.Bot.uin) {
+ if (e.isGroup) {
+ // 群聊判断权限
+ if (!e.isMaster && !e.member.is_owner && !e.member.is_admin) {
+ return logger.warn(`${e.logFnc}该群员权限不足`)
+ }
+ } else {
+ // 私聊判断是否为Bot消息
+ return logger.warn(`${e.logFnc}引用不是Bot消息`)
+ }
+ }
+ if (source.message[0].type === 'file' && e.isGroup) {
+ // 删除文件
+ logger.info(`${e.logFnc}执行删除文件`)
+ await this.Bot.acquireGfs(e.group_id).rm(source.message[0].fid)
+ } else {
+ // 撤回消息
+ logger.info(`${e.logFnc}执行撤回消息`)
+ await target.recallMsg(source.message_id)
+ }
+ await common.sleep(300)
+ let recallcheck = await this.Bot.getMsg(source.message_id)
+ if (recallcheck && recallcheck.message_id == source.message_id) {
+ let msg
+ if (e.isGroup) {
+ if (!e.group.is_admin && !e.group.is_owner) {
+ msg = '人家连管理员都木有,怎么撤回两分钟前的消息或别人的消息辣o(´^`)o'
+ } else {
+ msg = '干不赢这个淫的辣(`Δ´)ゞ'
+ }
+ } else {
+ msg = '过了两分钟,吃不掉辣(o`ε´o)'
+ }
+ return e.reply(msg, true, { recallMsg: 5 })
+ }
+ if (e.isGroup) await e.recall()
+ }
+
+ // 开关好友添加
+ async FriendSwitch(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let res = await new QQApi(e).addFriendSwitch(/开启/.test(e.msg) ? 1 : 2)
+ if (!res) return e.reply(API_ERROR)
+ e.reply(res.ActionStatus)
+ }
+
+ // 好友申请方式
+ async FriendType(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = friendTypeReg.exec(e.msg)
+ if (regRet[1] == 0) return e.reply('1为允许所有人,2为需要验证,3为问答正确问答(需填问题和答案,格式为:#更改好友申请方式3 问题 答案)')
+ // 单独处理
+ if ((!regRet[3] || !regRet[4]) && regRet[1] == 3) return e.reply('❎ 请正确输入问题和答案!')
+
+ let res = await new QQApi(e).setFriendType(regRet[1], regRet[3], regRet[4])
+ if (!res) return e.reply(API_ERROR)
+ if (res.ec != 0) return e.reply('❎ 修改失败\n' + JSON.stringify(res))
+ e.reply(res.msg)
+ }
+
+ /** 开关戳一戳 */
+ async Cyc(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let result = await new QQApi(e).setcyc(/开启/.test(e.msg) ? 0 : 1)
+ if (!result) return e.reply(API_ERROR)
+
+ if (result.ret != 0) return e.reply('❎ 未知错误\n' + JSON.stringify(result))
+ e.reply(`✅ 已${/开启/.test(e.msg) ? '开启' : '关闭'}戳一戳功能`)
+ }
+
+ async setModel(e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let model = e.msg.replace(/#|设置机型/g, '')
+ let res = await new QQApi(e).setModel(model).catch(err => logger.error(err))
+ e.reply(_.get(res, ['13031', 'data', 'rsp', 'iRet']) == 0 ? '设置成功' : '设置失败')
+ }
+
+ async BlockOne() {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ const configPath = process.cwd().replace(/\\/g, '/') + '/config/config/other.yaml'
+ /** 判断at */
+ if (this.e.at) {
+ try {
+ const yamlContentBuffer = await fs.promises.readFile(configPath)
+ /** 转字符串 */
+ const yamlContent = yamlContentBuffer.toString('utf-8')
+ const data = yaml.parse(yamlContent)
+ if (!data.blackQQ.includes(this.e.at)) {
+ data.blackQQ.push(this.e.at)
+ const updatedYaml = yaml.stringify(data, { quote: false })
+ /** 删除引号 */
+ const resultYaml = updatedYaml.replace(/"/g, '')
+ await fs.promises.writeFile(configPath, resultYaml, 'utf-8')
+ await this.e.reply(`✅ 已拉黑${this.e.at}`)
+ } else {
+ await this.e.reply(`❎ 拉黑失败,黑名单中已存在`)
+ }
+ } catch (error) {
+ await this.e.reply(`❎ 拉黑失败,发生了未知的错误`)
+ logger.error(error)
+ }
+ } else {
+ /** 非TRSS-Yunzai仅匹配5-10位非0开头数字 */
+ if (!Version.name == `TRSS-Yunzai`) {
+ const regex = /^#?拉黑(群|群聊)?[1-9]\d{4,9}$/
+ const match = this.e.msg.match(regex)
+ if (match) {
+ const blackId = match[3]
+ if (/^\d+$/.test(blackId)) {
+ this.blackResult = blackId
+ } else {
+ await this.e.reply(`❎ 拉黑失败,QQ或群号不合法`)
+ }
+ }
+ } else {
+ /** TRSS-Yunzai匹配所有字符 */
+ const blackId = this.e.msg.replace(/#|拉黑|群|群聊/g, '').trim()
+ if (blackId == "") {
+ await this.e.reply(`❎ 拉黑失败,没有键入QQ或群号`)
+ return true
+ }
+ this.blackResult = blackId
+ }
+ try {
+ const yamlContentBuffer = await fs.promises.readFile(configPath)
+ const yamlContent = yamlContentBuffer.toString('utf-8')
+ const data = yaml.parse(yamlContent)
+ if (!this.e.msg.includes(`群`)) {
+ if (!data.blackQQ.includes(this.blackResult)) {
+ data.blackQQ.push(this.blackResult)
+ const updatedYaml = yaml.stringify(data, { quote: false })
+ const resultYaml = updatedYaml.replace(/"/g, '')
+ await fs.promises.writeFile(configPath, resultYaml, 'utf-8')
+ await this.e.reply(`✅ 已拉黑${this.blackResult}`)
+ } else {
+ await this.e.reply(`❎ 拉黑失败,${this.blackResult}在黑名单中已存在`)
+ }
+ } else {
+ if (!data.blackGroup.includes(this.blackResult)) {
+ data.blackGroup.push(this.blackResult)
+ const updatedYaml = yaml.stringify(data, { quote: false })
+ const resultYaml = updatedYaml.replace(/"/g, '')
+ await fs.promises.writeFile(configPath, resultYaml, 'utf-8')
+ await this.e.reply(`✅ 已拉黑群聊${this.blackResult}`)
+ } else {
+ await this.e.reply(`❎ 拉黑失败,${this.blackResult}在黑名单中已存在`)
+ }
+ }
+ } catch (error) {
+ await this.e.reply(`❎ 拉黑失败,发生了未知的错误`)
+ logger.error(error)
+ }
+ }
+ }
+ async CancelBlockOne() {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ const configPath = process.cwd().replace(/\\/g, '/') + '/config/config/other.yaml'
+ if (this.e.at) {
+ try {
+ const yamlContentBuffer = await fs.promises.readFile(configPath)
+ const yamlContent = yamlContentBuffer.toString('utf-8')
+ const data = yaml.parse(yamlContent)
+ if (data && data.blackQQ && Array.isArray(data.blackQQ)) {
+ const itemToRemove = this.e.at.toString()
+ data.blackQQ = data.blackQQ.filter(item => item.toString() !== itemToRemove)
+ const updatedYaml = yaml.stringify(data)
+ await fs.promises.writeFile(configPath, updatedYaml, 'utf-8')
+ await this.e.reply(`✅ 已取消拉黑${this.e.at}`)
+ } else {
+ await this.e.reply(`❎ 找不到要取消拉黑的对象`)
+ }
+ } catch (error) {
+ await this.e.reply(`❎ 取消拉黑失败,发生了未知的错误`)
+ logger.error(error)
+ }
+ } else {
+ if (!Version.name == `TRSS-Yunzai`) {
+ const regex = /^#?(取消|删除|移除)拉黑(群|群聊)?[1-9]\d{4,9}$/
+ const match = this.e.msg.match(regex)
+ if (match) {
+ const blackId = match[3]
+ if (/^\d+$/.test(blackId)) {
+ this.blackResult = blackId
+ } else {
+ await this.e.reply(`❎ 取消拉黑失败,QQ或群号不合法`)
+ }
+ }
+ } else {
+ const blackId = this.e.msg.replace(/#|取消|删除|移除|拉黑|群|群聊/g, '').trim()
+ if (blackId == "") {
+ await this.e.reply(`❎ 取消拉黑失败,没有键入QQ或群号`)
+ return true
+ }
+ this.blackResult = blackId
+ }
+ try {
+ const yamlContentBuffer = await fs.promises.readFile(configPath)
+ const yamlContent = yamlContentBuffer.toString('utf-8')
+ const data = yaml.parse(yamlContent)
+ if (!this.e.msg.includes(`群`)) {
+ if (data && data.blackQQ && Array.isArray(data.blackQQ)) {
+ const itemToRemove = this.blackResult.toString()
+ data.blackQQ = data.blackQQ.filter(item => item.toString() !== itemToRemove)
+ const updatedYaml = yaml.stringify(data)
+ await fs.promises.writeFile(configPath, updatedYaml, 'utf-8')
+ await this.e.reply(`✅ 已取消拉黑${this.blackResult}`)
+ } else {
+ await this.e.reply(`❎ 找不到要取消拉黑的对象`)
+ }
+ } else {
+ if (data && data.blackGroup && Array.isArray(data.blackGroup)) {
+ const itemToRemove = this.blackResult.toString()
+ data.blackGroup = data.blackGroup.filter(item => item.toString() !== itemToRemove)
+ const updatedYaml = yaml.stringify(data)
+ await fs.promises.writeFile(configPath, updatedYaml, 'utf-8')
+ await this.e.reply(`✅ 已取消拉黑群聊${this.blackResult}`)
+ } else {
+ await this.e.reply(`❎ 找不到要取消拉黑的对象`)
+ }
+ }
+ } catch (error) {
+ await this.e.reply(`❎ 取消拉黑失败,发生了未知的错误`)
+ logger.error(error)
+ }
+ }
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/bika.js b/Yunzai/plugins/yenai-plugin/apps/bika.js
new file mode 100644
index 0000000000000000000000000000000000000000..50d685add28e620dc999a1ab24036a1642e29595
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/bika.js
@@ -0,0 +1,165 @@
+import { Bika, common, Pixiv } from '../model/index.js'
+import { Config } from '../components/index.js'
+import { Admin } from './admin.js'
+
+// 汉字数字匹配正则
+const numReg = '[零一壹二两三四五六七八九十百千万亿\\d]+'
+const Prefix = '(bika|哔咔)'
+// 命令正则
+const searchReg = new RegExp(`^#?${Prefix}(类别|作者|高级)?搜索(.*?)(第(${numReg})页)?$`)
+const comicPageReg = new RegExp(`^#?${Prefix}id(.*?)(第(${numReg})页)?(第(${numReg})话)?$`)
+export class NewBika extends plugin {
+ constructor () {
+ super({
+ name: '椰奶哔咔',
+ event: 'message',
+ priority: 2000,
+ rule: [
+ {
+ reg: searchReg,
+ fnc: 'search'
+ },
+ {
+ reg: comicPageReg,
+ fnc: 'comicPage'
+ },
+ {
+ reg: `^#?${Prefix}看\\d+$`,
+ fnc: 'viewComicPage'
+ },
+ {
+ reg: `^#?${Prefix}下一页$`,
+ fnc: 'nextComicPage'
+ },
+ {
+ reg: `^#?${Prefix}下一话$`,
+ fnc: 'nextChapter'
+ },
+ {
+ reg: `^#?${Prefix}类别列表$`,
+ fnc: 'categories'
+ },
+ {
+ reg: `^#?${Prefix}(详情|细节)(.*)$`,
+ fnc: 'comicDetail'
+ },
+ {
+ reg: `^#?${Prefix}修改图片质量(.*)$`,
+ fnc: 'imageQuality'
+ },
+ {
+ reg: `^#?${Prefix}(开启|关闭)直连$`,
+ fnc: 'directConnection'
+ }
+ ]
+
+ })
+ }
+
+ /** 搜索 */
+ async search (e) {
+ if (!await this._Authentication(e)) return
+ e.reply(Pixiv.startMsg)
+ let regRet = e.msg.match(searchReg)
+ let page = common.translateChinaNum(regRet[5])
+ await Bika.search(regRet[3], page, regRet[2])
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 漫画页面 */
+ async comicPage (e) {
+ if (!await this._Authentication(e)) return
+ e.reply(Pixiv.startMsg)
+ let regRet = e.msg.match(comicPageReg)
+ let page = common.translateChinaNum(regRet[4])
+ let order = common.translateChinaNum(regRet[6])
+ await Bika.comicPage(regRet[2], page, order)
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 快速查看 */
+ async viewComicPage (e) {
+ if (!await this._Authentication(e)) return
+ let number = e.msg.match(/\d+/) - 1
+ await Bika.viewComicPage(number)
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 下一页 */
+ async nextComicPage (e) {
+ if (!await this._Authentication(e)) return
+ await Bika.next()
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 下一话 */
+ async nextChapter (e) {
+ if (!await this._Authentication(e)) return
+ await Bika.next('chapter')
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 类别列表 */
+ async categories (e) {
+ if (!await this._Authentication(e)) return
+ e.reply(Pixiv.startMsg)
+ await Bika.categories()
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 漫画细节 */
+ async comicDetail (e) {
+ if (!await this._Authentication(e)) return
+ e.reply(Pixiv.startMsg)
+ let id = e.msg.match(new RegExp(`#?${Prefix}(详情|细节)(.*)`))[3]
+ await Bika.comicDetail(id)
+ .then(res => common.recallSendForwardMsg(e, res, { oneMsg: true }))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 图片质量 */
+ async imageQuality (e) {
+ let quality = e.msg.match(new RegExp(`#?${Prefix}修改图片质量(.*)`))[2]
+ let imageQualityType = {
+ 低质量: 'low',
+ 中等质量: 'medium',
+ 高质量: 'high',
+ 原图: 'original'
+ }
+ if (!imageQualityType[quality] && !Object.values(imageQualityType).includes(quality)) return e.reply(`错误参数,支持的参数为${Object.keys(imageQualityType).join(',')}`)
+ let type = imageQualityType[quality] ?? quality
+ Config.modify('bika', 'imageQuality', type)
+ new Admin().SeSe_Settings(e)
+ }
+
+ /** 图片直连 */
+ async directConnection (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let now = Config.bika.bikaDirectConnection
+ let isSwitch = /开启/.test(e.msg)
+ if (now && isSwitch) return e.reply('❎ bika图片直连已处于开启状态')
+ if (!now && !isSwitch) return e.reply('❎ bika图片直连已处于关闭状态')
+ Config.modify('bika', 'bikaDirectConnection', isSwitch)
+ new Admin().SeSe_Settings(e)
+ }
+
+ async _Authentication (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ if (!common.checkSeSePermission(e, 'sesepro')) return false
+ if (!Config.bika.allowPM && !e.isGroup) {
+ e.reply('主人已禁用私聊该功能')
+ return false
+ }
+ if (!await common.limit(e.user_id, 'bika', Config.bika.limit)) {
+ e.reply('您已达今日「bika」次数上限', true, { at: true })
+ return false
+ }
+ return true
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/events/input.js b/Yunzai/plugins/yenai-plugin/apps/events/input.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca4ee0585c1f873eece394e8e2b2a6948324c861
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/events/input.js
@@ -0,0 +1,14 @@
+import { common } from '../../model/index.js'
+import { Config } from '../../components/index.js'
+
+Bot.on?.('internal.input', async (e) => {
+ if (!Config.whole.input) return false
+ // 判断是否主人消息
+ if (Config.masterQQ.includes(e.user_id)) return false
+ let msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[事件(${e.self_id}) - 对方${e.end ? '输入完毕' : '正在输入'}]\n`,
+ `好友账号:${e.user_id}`
+ ]
+ await common.sendMasterMsg(msg)
+})
diff --git a/Yunzai/plugins/yenai-plugin/apps/events/message.js b/Yunzai/plugins/yenai-plugin/apps/events/message.js
new file mode 100644
index 0000000000000000000000000000000000000000..6763fe71436039c7f8a57f39927976cf15a245fc
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/events/message.js
@@ -0,0 +1,193 @@
+import { common } from '../../model/index.js'
+import { Config } from '../../components/index.js'
+
+Bot.on?.('message', async (e) => {
+ // 判断是否存在消息
+ if (!e?.message?.length) return false
+ // 判断是否为机器人消息
+ if (e.user_id == (e.bot ?? Bot).uin) return false
+ // 判断是否主人消息
+ if (Config.masterQQ.includes(e.user_id)) return false
+ // 删除缓存时间
+ const deltime = Config.whole.deltime
+ // 判断群聊还是私聊
+ if (e.isGroup) {
+ // 关闭撤回停止存储
+ if (Config.getGroup(e.group_id).groupRecall) {
+ logger.debug(`[Yenai-Plugin]存储群消息${(e.group_id)}}=> ${e.message_id}`)
+ // 写入
+ await redis.set(
+ `notice:messageGroup:${e.message_id}`,
+ JSON.stringify(e.message),
+ { EX: deltime }
+ )
+ }
+ } else if (e.isPrivate) {
+ // 关闭撤回停止存储
+ if (Config.whole.PrivateRecall) {
+ logger.debug(`[Yenai-Plugin]存储私聊消息(${e.user_id})=> ${e.message_id}`)
+ // 写入
+ await redis.set(
+ `notice:messagePrivate:${e.message_id}`,
+ JSON.stringify(e.message),
+ { EX: deltime }
+ )
+ }
+ }
+ // 消息通知
+ let msg = null
+ let forwardMsg = null
+ if (
+ e.message[0].type == 'flash' &&
+ e.message_type === 'group'
+ ) {
+ if (!Config.getGroup(e.group_id).flashPhoto) return false
+ logger.info('[Yenai-Plugin]群聊闪照')
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`),
+ `[消息(${e.self_id}) - 闪照消息]\n`,
+ `发送人账号:${e.user_id}\n`,
+ `发送人昵称:${e.sender.nickname}\n`,
+ `来源群号:${e.group_id}\n`,
+ `来源群名:${e.group_name}\n`,
+ `闪照链接:${e.message[0].url}`
+ ]
+ } else if (
+ e.message[0].type == 'flash' &&
+ e.message_type === 'discuss' &&
+ Config.whole.flashPhoto
+ ) {
+ logger.info('[Yenai-Plugin]讨论组闪照')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 闪照消息]\n`,
+ `发送人账号:${e.user_id}\n`,
+ `发送人昵称:${e.sender.nickname}\n`,
+ `讨论组号:${e.discuss_id}\n`,
+ `讨论组名:${e.discuss_name}\n`,
+ `闪照链接:${e.message[0].url}`
+ ]
+ } else if (
+ e.message[0].type == 'flash' &&
+ e.message_type === 'private' &&
+ Config.whole.flashPhoto
+ ) {
+ logger.info('[Yenai-Plugin]好友闪照')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 闪照消息]\n`,
+ `发送人账号:${e.user_id}\n`,
+ `发送人昵称:${e.sender.nickname}\n`,
+ `闪照链接:${e.message[0].url}`
+ ]
+ } else if (e.message_type === 'private' && e.sub_type === 'friend') {
+ if (!Config.whole.privateMessage) return false
+
+ // 特殊消息处理
+ const arr = getMsgType(e.message)
+ if (arr) {
+ forwardMsg = arr.msg
+ e.message = arr.type
+ }
+ logger.info('[Yenai-Plugin]好友消息')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 好友消息]\n`,
+ `好友账号:${e.user_id}\n`,
+ `好友昵称:${e.sender.nickname}\n`,
+ '消息内容:',
+ ...e.message
+ ]
+ // 添加提示消息
+ const key = `yenai:notice:privateMessage:${e.user_id}`
+ if (!(await redis.get(key))) {
+ await redis.set(key, '1', { EX: 600 })
+ msg.push(
+ '\n-------------\n',
+ '引用该消息:回复 <内容>\n',
+ `或发送:回复 ${e.user_id} <内容>`
+ )
+ }
+ } else if (e.message_type === 'private' && e.sub_type === 'group') {
+ if (!Config.getGroup(e.group_id).grouptemporaryMessage) return false
+ // 特殊消息处理
+ const arr = getMsgType(e.message)
+ if (arr) {
+ forwardMsg = arr.msg
+ e.message = arr.type
+ }
+ logger.info('[Yenai-Plugin]群临时消息')
+ // 发送的消息
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 群临时消息]\n`,
+ `来源群号:${e.sender.group_id}\n`,
+ `发送人账号:${e.user_id}\n`,
+ '消息内容:',
+ ...e.message
+ ]
+ // 添加提示消息
+ const key = `yenai:notice:tempprivateMessage:${e.user_id}`
+ if (!(await redis.get(key))) {
+ await redis.set(key, '1', { EX: 600 })
+ msg.push(
+ '\n-------------\n',
+ '可回复 "加为好友" 添加好友\n或 "回复 <消息>"'
+ )
+ }
+ } else if (e.message_type === 'group') {
+ if (!Config.getGroup(e.group_id).groupMessage) return false
+ // 特殊消息处理
+ const arr = getMsgType(e.message)
+ if (arr) {
+ forwardMsg = arr.msg
+ e.message = arr.type
+ }
+ logger.info('[Yenai-Plugin]群聊消息')
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`),
+ `[消息(${e.self_id}) - 群聊消息]\n`,
+ `来源群号:${e.group_id}\n`,
+ `来源群名:${e.group_name}\n`,
+ `发送人账号:${e.user_id}\n`,
+ `发送人昵称:${e.sender.nickname}\n`,
+ '消息内容:',
+ ...e.message
+ ]
+ } else if (e.message_type === 'discuss') {
+ if (!Config.getGroup(e.group_id).groupMessage) return false
+ logger.info('[Yenai-Plugin]讨论组消息')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 群聊消息]\n`,
+ `来源讨论组号:${e.discuss_id}\n`,
+ `来源讨论组名:${e.discuss_name}\n`,
+ `发送人账号:${e.user_id}\n`,
+ `发送人昵称:${e.sender.nickname}\n`,
+ `消息内容:${e.raw_message}`
+ ]
+ } else {
+ return false
+ }
+ // 发送消息
+ await common.sendMasterMsg(msg)
+ if (forwardMsg) await common.sendMasterMsg(forwardMsg)
+})
+// 特殊消息处理
+function getMsgType (msg) {
+ const msgType = {
+ record: {
+ msg: segment.record(msg[0].url),
+ type: '[语音]'
+ },
+ video: {
+ msg: segment.video(msg[0].file),
+ type: '[视频]'
+ },
+ xml: {
+ msg,
+ type: '[合并消息]'
+ }
+ }
+ return msgType[msg[0].type]
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/events/notice_friend.js b/Yunzai/plugins/yenai-plugin/apps/events/notice_friend.js
new file mode 100644
index 0000000000000000000000000000000000000000..25cf2dc669c17ed9ad2507530c56b66bb29af9f7
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/events/notice_friend.js
@@ -0,0 +1,112 @@
+import { common } from '../../model/index.js'
+import { Config } from '../../components/index.js'
+
+Bot.on?.('notice.friend', async (e) => {
+ let msg
+ let forwardMsg
+ switch (e.sub_type) {
+ case 'increase': {
+ if (!Config.whole.friendNumberChange) return false
+ logger.info('[Yenai-Plugin]新增好友')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[通知(${e.self_id}) - 新增好友]\n`,
+ `好友账号:${e.user_id}\n`,
+ `好友昵称:${e.nickname}`
+ ]
+ break
+ }
+ case 'decrease': {
+ if (!Config.whole.friendNumberChange) return false
+ logger.info('[Yenai-Plugin]好友减少')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[通知(${e.self_id}) - 好友减少]\n`,
+ `好友账号:${e.user_id}\n`,
+ `好友昵称:${e.nickname}`
+ ]
+ break
+ }
+ case 'recall': {
+ if (!Config.whole.PrivateRecall) return false
+
+ if (e.user_id == (e.bot ?? Bot).uin) return false
+ // 主人撤回
+ if (Config.masterQQ.includes(e.user_id)) return false
+ logger.info('[Yenai-Plugin]好友撤回')
+ // 读取
+ let res = JSON.parse(
+ await redis.get(`notice:messagePrivate:${e.message_id}`)
+ )
+ // 无数据 return
+ if (!res) return false
+ const msgType = {
+ flash: {
+ msg: () => false,
+ type: ['[闪照]\n', '撤回闪照:', segment.image(res[0].url)]
+ },
+ record: {
+ msg: () => segment.record(res[0].url),
+ type: '[语音]'
+ },
+ video: {
+ msg: () => segment.video(res[0].file),
+ type: '[视频]'
+ },
+ xml: {
+ msg: () => res,
+ type: '[合并消息]'
+ }
+ }
+ if (msgType[res[0].type]) {
+ forwardMsg = msgType[res[0].type].msg()
+ res = msgType[res[0].type].type
+ }
+ // 消息
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 好友撤回消息]\n`,
+ `好友账号:${e.user_id}\n`,
+ `撤回时间:${formatDate(e.time)}\n`,
+ '撤回消息:',
+ ...res
+ ]
+ break
+ }
+ case 'poke': {
+ if (!Config.whole.privateMessage) return false
+ logger.info('[Yenai-Plugin]好友戳一戳')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[消息(${e.self_id}) - 戳一戳]\n`,
+ `来源账号:${e.user_id}`
+ ]
+ break
+ }
+ default:
+ return false
+ }
+ await common.sendMasterMsg(msg)
+ if (forwardMsg) await common.sendMasterMsg(forwardMsg)
+}
+)
+
+/** 时间转换 */
+function formatDate (time) {
+ let now = new Date(parseFloat(time) * 1000)
+ // 月
+ let month = now.getMonth() + 1
+ // 日
+ let date = now.getDate()
+ // 补0
+ if (month >= 1 && month <= 9) month = '0' + month
+ if (date >= 0 && date <= 9) date = '0' + date
+ // 时
+ let hour = now.getHours()
+ // 分
+ let minute = now.getMinutes()
+ // 补0
+ if (hour >= 1 && hour <= 9) hour = '0' + hour
+ if (minute >= 0 && minute <= 9) minute = '0' + minute
+ return `${month}-${date} ${hour}:${minute} `
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/events/notice_group.js b/Yunzai/plugins/yenai-plugin/apps/events/notice_group.js
new file mode 100644
index 0000000000000000000000000000000000000000..88d4a0f1639ff87ef4a25c1f601b55af9305d4ff
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/events/notice_group.js
@@ -0,0 +1,272 @@
+import { common } from '../../model/index.js'
+import { Config } from '../../components/index.js'
+import moment from 'moment'
+
+Bot.on?.('notice.group', async (e) => {
+ let msg
+ let forwardMsg
+ switch (e.sub_type) {
+ case 'increase': {
+ if (e.user_id === (e.bot ?? Bot).uin) {
+ if (!Config.getGroup(e.group_id).groupNumberChange) return false
+
+ logger.info('[Yenai-Plugin]新增群聊')
+
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`),
+ `[通知(${e.self_id}) - 新增群聊]\n`,
+ `新增群号:${e.group_id}`
+ ]
+ } else {
+ if (!Config.getGroup(e.group_id).groupMemberNumberChange) return false
+
+ logger.info('[Yenai-Plugin]新增群员')
+
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`),
+ `[通知(${e.self_id}) - 新增群员]\n`,
+ `群号:${e.group_id}\n`,
+ `新成员账号:${e.user_id}\n`,
+ `新成员昵称:${e.nickname}`
+ ]
+ }
+ break
+ }
+ case 'decrease': {
+ if (e.dismiss) {
+ if (!Config.getGroup(e.group_id).groupNumberChange) return false
+
+ logger.info('[Yenai-Plugin]群聊被解散')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 群聊被解散]\n`,
+ `操作人账号:${e.operator_id}\n`,
+ `解散群号:${e.group_id}`
+ ]
+ } else if (
+ e.user_id === (e.bot ?? Bot).uin &&
+ e.operator_id !== (e.bot ?? Bot).uin
+ ) {
+ if (!Config.getGroup(e.group_id).groupNumberChange) return false
+
+ logger.info('[Yenai-Plugin]机器人被踢')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 机器人被踢]\n`,
+ `操作人账号:${e.operator_id}\n`,
+ `被踢群号:${e.group_id}`
+ ]
+ } else if (
+ e.user_id === (e.bot ?? Bot).uin &&
+ e.operator_id === (e.bot ?? Bot).uin
+ ) {
+ if (!Config.getGroup(e.group_id).groupNumberChange) return false
+
+ logger.info('[Yenai-Plugin]机器人退群')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 机器人退群]\n`,
+ `退出群号:${e.group_id}`
+ ]
+ } else if (e.operator_id === e.user_id) {
+ if (!Config.getGroup(e.group_id).groupMemberNumberChange) return false
+
+ logger.info('[Yenai-Plugin]群员退群')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 群员退群]\n`,
+ `退群人账号:${e.user_id}\n`,
+ `退群人昵称:${e.member.nickname}\n`,
+ `退群人群名片:${e.member.card}\n`,
+ `退出群号:${e.group_id}`
+ ]
+ } else if (e.operator_id !== e.user_id) {
+ if (!Config.getGroup(e.group_id).groupMemberNumberChange) return false
+
+ logger.info('[Yenai-Plugin]群员被踢')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 群员被踢]\n`,
+ `操作人账号:${e.operator_id}\n`,
+ `被踢人账号:${e.user_id}\n`,
+ `被踢人昵称:${e.member.nickname}\n`,
+ `被踢人群名片:${e.member.card}\n`,
+ `被踢群号:${e.group_id}`
+ ]
+ }
+ break
+ }
+ // 群管理变动
+ case 'admin': {
+ if (!Config.getGroup(e.group_id).groupAdminChange) return false
+
+ e.set ? logger.info('[Yenai-Plugin]机器人被设置管理') : logger.info('[Yenai-Plugin]机器人被取消管理')
+ if (e.user_id === (e.bot ?? Bot).uin) {
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ e.set
+ ? `[通知(${e.self_id}) - 机器人被设置管理]:\n`
+ : `[通知(${e.self_id}) - 机器人被取消管理]:\n`,
+ `被操作群号:${e.group_id}`
+ ]
+ } else {
+ e.set ? logger.info('[Yenai-Plugin]新增群管理员') : logger.info('[Yenai-Plugin]取消群管理员')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ e.set ? `[通知(${e.self_id}) - 新增群管理员]:\n` : `[通知(${e.self_id}) - 取消群管理员]:\n`,
+ `被操作账号:${e.user_id}\n`,
+ `被操作群号:${e.group_id}`
+ ]
+ }
+ break
+ }
+ // 禁言 (这里仅处理机器人被禁言)
+ case 'ban': {
+ const forbiddenTime = common.formatTime(e.duration, 'default')
+
+ if (!Config.getGroup(e.group_id).botBeenBanned) return false
+
+ if (e.user_id != (e.bot ?? Bot).uin) return false
+
+ if (e.duration == 0) {
+ logger.info('[Yenai-Plugin]机器人被解除禁言')
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 机器人被解除禁言]\n`,
+ `处理人账号:${e.operator_id}\n`,
+ `处理群号:${e.group_id}`
+ ]
+ } else if (e.user_id === (e.bot ?? Bot).uin) {
+ logger.info('[Yenai-Plugin]机器人被禁言')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 机器人被禁言]\n`,
+ `禁言人账号:${e.operator_id}\n`,
+ `禁言群号:${e.group_id}\n`,
+ `禁言时长:${forbiddenTime}`
+ ]
+ }
+ break
+ }
+ // 群转让
+ case 'transfer': {
+ if (!Config.getGroup(e.group_id).groupNumberChange) return false
+
+ logger.info('[Yenai-Plugin]群聊转让')
+
+ msg = [
+ segment.image(
+ `https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`
+ ),
+ `[通知(${e.self_id}) - 群聊转让]\n`,
+ `转让群号:${e.group_id}\n`,
+ `旧群主:${e.operator_id}\n`,
+ `新群主:${e.user_id}`
+ ]
+ break
+ }
+ // 群撤回
+ case 'recall': {
+ // 开启或关闭
+ if (!Config.getGroup(e.group_id).groupRecall) return false
+ // 是否为机器人撤回
+ if (e.user_id == (e.bot ?? Bot).uin) return false
+ // 是否为主人撤回
+ if (Config.masterQQ.includes(e.user_id)) return false
+ // 读取
+ let res = JSON.parse(
+ await redis.get(`notice:messageGroup:${e.message_id}`)
+ )
+ // 无数据 return出去
+ if (!res) return false
+ // 不同消息处理
+ let special = ''
+ let msgType = {
+ flash: {
+ msg: () => e.group.makeForwardMsg([
+ {
+ message: segment.image(res[0].url),
+ nickname: e.group.pickMember(e.user_id).card,
+ user_id: e.user_id
+ }
+ ]),
+ type: '[闪照]'
+ },
+ record: {
+ msg: () => segment.record(res[0].url),
+ type: '[语音]'
+ },
+ video: {
+ msg: () => segment.video(res[0].file),
+ type: '[视频]'
+ },
+ xml: {
+ msg: () => res,
+ type: '[合并消息]'
+ }
+ }
+ if (msgType[res[0].type]) {
+ forwardMsg = await msgType[res[0].type].msg()
+ special = msgType[res[0].type].type
+ } else {
+ // 正常处理
+ forwardMsg = await (e.bot ?? Bot).pickFriend(Config.masterQQ[0]).makeForwardMsg([
+ {
+ message: res,
+ nickname: e.group.pickMember(e.user_id).card,
+ user_id: e.user_id
+ }
+ ])
+ }
+ // 判断是否管理撤回
+ let isManage = ''
+ if (e.operator_id != e.user_id) {
+ isManage = `撤回管理:${e.group.pickMember(e.operator_id).card}(${e.operator_id
+ })\n`
+ }
+ isManage ? logger.info('[Yenai-Plugin]群聊管理撤回') : logger.info('[Yenai-Plugin]群聊撤回')
+ // 发送的消息
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/100`),
+ `[通知(${e.self_id}) - 群聊${isManage ? '管理' : ''}撤回]\n`,
+ `撤回群名:${e.group_name}\n`,
+ `撤回群号:${e.group_id}\n`,
+ isManage,
+ `${isManage ? '被撤回人' : '撤回人员'}:${e.group.pickMember(e.user_id).card
+ }(${e.user_id})\n`,
+ `撤回时间:${moment(e.time * 1000).format('MM-DD HH:mm:ss')}`,
+ special ? `\n特殊消息:${special}` : ''
+ ]
+ break
+ }
+ default:
+ return false
+ }
+ await common.sendMasterMsg(msg)
+ if (forwardMsg) await common.sendMasterMsg(forwardMsg)
+})
diff --git a/Yunzai/plugins/yenai-plugin/apps/events/request.js b/Yunzai/plugins/yenai-plugin/apps/events/request.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d55b8318563042cbc8ec38d7e37aaa234c596e3
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/events/request.js
@@ -0,0 +1,83 @@
+import cfg from '../../../../lib/config/config.js'
+import { common } from '../../model/index.js'
+import { Config } from '../../components/index.js'
+const ROLE_MAP = {
+ admin: '群管理',
+ owner: '群主',
+ member: '群员'
+}
+
+Bot.on?.('request', async (e) => {
+ let msg = ''
+ switch (e.request_type) {
+ case 'group':
+ switch (e.sub_type) {
+ case 'invite':
+ if (!Config.whole.groupInviteRequest) return false
+ if (cfg.masterQQ.includes(e.user_id)) return false
+ logger.info('[Yenai-Plugin]邀请机器人进群')
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/0`),
+ `[通知(${e.self_id}) - 邀请机器人进群]\n`,
+ `目标群号:${e.group_id}\n`,
+ `目标群名:${e.group_name}\n`,
+ `邀请人账号:${e.user_id}\n`,
+ `邀请人昵称:${e.nickname}\n`,
+ `邀请人群身份:${ROLE_MAP[e.role]}\n`,
+ `邀请码:${e.seq}\n`
+ ]
+ if (cfg.other.autoQuit <= 0) {
+ msg.push('----------------\n可引用该消息回复"同意"或"拒绝"')
+ } else {
+ msg.push('已自动处理该邀请')
+ }
+ break
+ case 'add':
+ if (Config.groupAdd.openGroup.includes(e.group_id)) {
+ let msg = [`${Config.groupAdd.msg}\n`,
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `QQ号:${e.user_id}\n`,
+ `昵称:${e.nickname}\n`,
+ `${e.comment}`
+ ]
+ if (e.inviter_id !== undefined) { msg.push(`邀请人:${e.inviter_id}`) }
+ let sendmsg = await (e.bot ?? Bot).pickGroup(e.group_id).sendMsg(msg)
+ await redis.set(`yenai:groupAdd:${sendmsg.message_id}`, e.user_id, { EX: 3600 })
+ }
+ if (!Config.getGroup(e.group_id).addGroupApplication) return false
+ logger.info('[Yenai-Plugin]加群申请')
+ msg = [
+ segment.image(`https://p.qlogo.cn/gh/${e.group_id}/${e.group_id}/0`),
+ `[通知(${e.self_id}) - 加群申请]\n`,
+ `群号:${e.group_id}\n`,
+ `群名:${e.group_name}\n`,
+ `账号:${e.user_id}\n`,
+ `昵称:${e.nickname}`,
+ e.tips ? `\nTip:${e.tips}` : '',
+ `\n${e.comment}`
+ ]
+ break
+ }
+ break
+ case 'friend':
+ if (!Config.whole.friendRequest) return false
+ logger.info('[Yenai-Plugin]好友申请')
+ msg = [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`),
+ `[通知(${e.self_id}) - 添加好友申请]\n`,
+ `申请人账号:${e.user_id}\n`,
+ `申请人昵称:${e.nickname}\n`,
+ `申请来源:${e.source || '未知'}\n`,
+ `附加信息:${e.comment || '无附加信息'}\n`
+ ]
+ if (cfg.other.autoFriend == 1) {
+ msg.push('Tip:已被 Yunzai 自动处理')
+ } else {
+ msg.push(
+ `-------------\n可回复:#同意好友申请${e.user_id} \n或引用该消息回复"同意"或"拒绝"`
+ )
+ }
+ break
+ }
+ await common.sendMasterMsg(msg)
+})
diff --git a/Yunzai/plugins/yenai-plugin/apps/fun.js b/Yunzai/plugins/yenai-plugin/apps/fun.js
new file mode 100644
index 0000000000000000000000000000000000000000..fd3d5e774edad571f1034f37868eca57dc26ee09
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/fun.js
@@ -0,0 +1,397 @@
+import _ from 'lodash'
+import fetch from 'node-fetch'
+import plugin from '../../../lib/plugins/plugin.js'
+import { Config } from '../components/index.js'
+import { faildsImgs, heisiType, pandadiuType, successImgs } from '../constants/fun.js'
+import { QQApi, common, funApi, memes, uploadRecord } from '../model/index.js'
+
+/** API请求错误文案 */
+const API_ERROR = '❎ 出错辣,请稍后重试'
+
+/** 开始执行文案 */
+const START_EXECUTION = '椰奶产出中......'
+
+const picApis = Config.getConfig('picApi')
+/** 解析匹配模式 */
+const picApiKeys = []
+
+_.forIn(picApis, (values, key) => {
+ let mode = values.mode !== undefined ? values.mode : picApis.mode
+ key = key.split('|').map(item => mode ? '^' + item + '$' : item).join('|')
+ picApiKeys.push(key)
+})
+
+const apiReg = new RegExp(`(${picApiKeys.join('|')}|^jktj$|^接口统计$)`)
+
+export class Fun extends plugin {
+ constructor() {
+ super({
+ name: '椰奶娱乐',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: '^#唱歌$',
+ fnc: 'Sing'
+ },
+ {
+ reg: '^#支付宝到账',
+ fnc: 'ZFB'
+ },
+ {
+ reg: '^#(([\u4e00-\u9fa5]{2,6})-)?([\u4e00-\u9fa5]{2,6})?翻译(.*)$',
+ fnc: 'youdao'
+ },
+ {
+ reg: '^#?((我要|给我)?(资料卡)?(点赞)?(赞|超|操|草|抄|吵|炒)我)|((赞|超|操|草|抄|吵|炒)(他|她|它|TA|ta|Ta))$',
+ fnc: 'thumbUp'
+ },
+ {
+ reg: 'github.com/[a-zA-Z0-9-]{1,39}/[a-zA-Z0-9_-]{1,100}',
+ fnc: 'GH'
+ },
+ {
+ reg: '^#?coser$',
+ fnc: 'coser'
+ },
+ // {
+ // reg: `^#?来点(${Object.keys(heisiType).join('|')})$`,
+ // fnc: 'heisiwu'
+ // },
+ {
+ reg: '^#?铃声搜索',
+ fnc: 'lingsheng'
+ },
+ {
+ reg: '^#?半次元话题$',
+ fnc: 'bcyTopic'
+ },
+ {
+ reg: apiReg,
+ fnc: 'picture'
+ },
+ // {
+ // reg: '^#?来点神秘图(\\d+|s.*)?$',
+ // fnc: 'mengdui'
+ // },
+ {
+ reg: `^#(${Object.keys(pandadiuType).join('|')})?acg`,
+ fnc: 'acg'
+ },
+ {
+ reg: `^#来点(${Object.keys(funApi.xiurenTypeId).join('|')})$`,
+ fnc: 'xiuren'
+ }
+
+ ]
+ })
+ }
+
+ /** 随机唱鸭 */
+ async Sing(e) {
+ let data = await funApi.randomSinging()
+ if (data.error) return e.reply(data.error)
+ await e.reply(await uploadRecord(data.audioUrl, 0, false))
+ await e.reply(data.lyrics)
+ }
+
+ /** 支付宝语音 */
+ async ZFB(e) {
+ let amount = parseFloat(e.msg.replace(/#|支付宝到账|元|圆/g, '').trim())
+
+ if (!/^\d+(\.\d{1,2})?$/.test(amount)) return e.reply('你觉得这河里吗!!', true)
+
+ if (!(amount >= 0.01 && amount <= 999999999999.99)) {
+ return e.reply('数字大小超出限制,支持范围为0.01~999999999999.99')
+ }
+ e.reply([segment.record(`https://mm.cqu.cc/share/zhifubaodaozhang/mp3/${amount}.mp3`)])
+ }
+
+ /** 有道翻译 */
+ async youdao(e) {
+ const msg = e.msg.match(/#(([\u4e00-\u9fa5]{2,6})-)?([\u4e00-\u9fa5]{2,6})?翻译(.*)/)
+ // 如果是在群聊中回复,则获取上一条消息作为翻译内容
+ if (e.source) {
+ const source = e.isGroup
+ ? (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ : (await e.friend.getChatHistory(e.source.time, 1)).pop()
+
+ msg[4] = source.message
+ .filter(item => item.type === 'text')
+ .map(item => item.text).join('')
+ }
+ const results = await funApi.youdao(msg[4], msg[3], msg[2])
+ e.reply(results, true)
+ }
+
+ /** 点赞 */
+ async thumbUp(e) {
+ if (e.msg.includes(`超`, `操`, `草`, `抄`, `吵`, `炒`)) {
+ this.do = `超`
+ } else {
+ this.do = `赞`
+ }
+ if ((e.bot ?? Bot).config?.platform == 3) {
+ return logger.error(`${e.logFnc}手表协议暂不支持点赞请更换协议后重试`)
+ }
+ /** 判断是赞自己还是赞别人 */
+ if (e.at && e.msg.includes(`他`, `她`, `它`, `TA`, `ta`, `Ta`)) {
+ /** 判断是否为好友 */
+ let isFriend = await (e.bot ?? Bot).fl.get(e.at)
+ let allowLikeByStrangers = Config.whole.Strangers_love
+ if (!isFriend && !allowLikeByStrangers) return e.reply(`不加好友不${this.do}🙄`, true)
+ /** 执行点赞 */
+ let n = 0
+ let failsMsg = `今天已经${this.do}过了,还搁这讨${this.do}呢!!!`
+ while (true) {
+ let res = null
+ try {
+ res = await new QQApi(e).thumbUp(e.at, 10)
+ } catch (error) {
+ logger.error(error)
+ return common.handleException(e, error)
+ }
+ logger.debug(`${e.logFnc}给${e.at}点赞`, res)
+ if (res.code != 0) {
+ if (res.code == 1) {
+ failsMsg = `${this.do}失败,请检查是否开启陌生人点赞或添加好友`
+ } else {
+ if (this.do == `超`) {
+ failsMsg = res.msg.replace(/给/g, '超').replace(/点/g, '').replace(/个赞/g, '下')
+ } else {
+ failsMsg = res.msg
+ }
+ }
+ break
+ } else {
+ n += 10
+ }
+ }
+ let successMsg = `给${e.at}${this.do}了${n}下哦,记得回我~ ${isFriend ? `` : `(如${this.do}失败请添加好友)`}`
+ const avatar = `https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.at}`
+ const successFn = _.sample(['ganyu', 'zan'])
+
+ /** 判断点赞是否成功 */
+ let msg = n > 0
+ ? [
+ `\n${successMsg}`,
+ segment.image((await memes[successFn](avatar)) ||
+ _.sample(successImgs) + e.user_id)
+ ]
+ : [
+ `\n${failsMsg}`,
+ segment.image((await memes.crawl(avatar)) ||
+ _.sample(faildsImgs) + e.user_id)
+ ]
+
+ /** 回复 */
+ e.reply(msg, true, { at: e.at })
+ } else if (!e.msg.includes(`他`, `她`, `它`, `TA`, `ta`, `Ta`)) {
+ /** 判断是否为好友 */
+ let isFriend = await (e.bot ?? Bot).fl.get(e.user_id)
+ let allowLikeByStrangers = Config.whole.Strangers_love
+ if (!isFriend && !allowLikeByStrangers) return e.reply(`不加好友不${this.do}🙄`, true)
+
+ /** 执行点赞 */
+ let n = 0
+ let failsMsg = `今天已经${this.do}过了,还搁这讨${this.do}呢!!!`
+ while (true) {
+ let res = null
+ try {
+ res = await new QQApi(e).thumbUp(e.user_id, 10)
+ } catch (error) {
+ logger.error(error)
+ return common.handleException(e, error)
+ }
+ logger.debug(`${e.logFnc}给${e.user_id}点赞`, res)
+ if (res.code != 0) {
+ if (res.code == 1) {
+ failsMsg = `${this.do}失败,请检查是否开启陌生人点赞或添加好友`
+ } else {
+ if (this.do == `超`) {
+ failsMsg = res.msg.replace(/给/g, '超').replace(/点/g, '').replace(/个赞/g, '下')
+ } else {
+ failsMsg = res.msg
+ }
+ }
+ break
+ } else {
+ n += 10
+ }
+ }
+ let successMsg = `给你${this.do}了${n}下哦,记得回我~ ${isFriend ? `` : `(如${this.do}失败请添加好友)`}`
+ const avatar = `https://q1.qlogo.cn/g?b=qq&s=100&nk=${e.user_id}`
+ const successFn = _.sample(['ganyu', 'zan'])
+
+ /** 判断点赞是否成功 */
+ let msg = n > 0
+ ? [
+ `\n${successMsg}`,
+ segment.image((await memes[successFn](avatar)) ||
+ _.sample(successImgs) + e.user_id)
+ ]
+ : [
+ `\n${failsMsg}`,
+ segment.image((await memes.crawl(avatar)) ||
+ _.sample(faildsImgs) + e.user_id)
+ ]
+
+ /** 回复 */
+ e.reply(msg, true, { at: true })
+ }
+ }
+
+ // github
+ async GH(e) {
+ const api = 'https://opengraph.githubassets.com'
+
+ let reg = /github.com\/[a-zA-Z0-9-]{1,39}\/[a-zA-Z0-9_-]{1,100}(?:\/(?:pull|issues)\/\d+)?/
+ const isMatched = e.msg.match(reg)
+
+ const id = 'Yenai'
+ if (isMatched) {
+ // const res = isMatched[0].split('/')
+ let path = isMatched[0].replace('github.com/', '')
+ e.reply(segment.image(`${api}/${id}/${path}`))
+ // const [user, repo] = [res[1], res[2].split('#')[0]]
+ // e.reply(segment.image(`${api}/${id}/${user}/${repo}`))
+ }
+ }
+
+ // coser
+ async coser(e) {
+ if (!common.checkSeSePermission(e)) return false
+
+ e.reply(START_EXECUTION)
+ await funApi.coser()
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // cos/acg搜索
+ async acg(e) {
+ if (!common.checkSeSePermission(e)) return false
+ e.reply(START_EXECUTION)
+ const reg = new RegExp(`^#(${Object.keys(pandadiuType).join('|')})?acg(.*)$`)
+ const type = e.msg.match(reg)
+ await funApi.pandadiu(type[1], type[2])
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 黑丝
+ async heisiwu(e) {
+ if (!common.checkSeSePermission(e, 'sesepro')) return false
+
+ e.reply(START_EXECUTION)
+ // 获取类型
+ const { type, page } = heisiType[e.msg.match(/#?来点(.*)/)[1]]
+ await funApi.heisiwu(type, page)
+ .then(res => common.recallSendForwardMsg(e, _.take(res, 20)))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 萌堆
+ async mengdui(e) {
+ if (!common.checkSeSePermission(e, 'sesepro')) return false
+ // 开始执行
+ e.reply(START_EXECUTION)
+ let regRet = e.msg.match(/#?来点神秘图(s)?(.*)/)
+ await funApi.mengdui(regRet[2], regRet[1])
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ async xiuren(e) {
+ if (!common.checkSeSePermission(e, 'pro')) return false
+ // 开始执行
+ e.reply(START_EXECUTION)
+ await funApi.xiuren(e.msg.replace(/#?来点/, ''))
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 铃声多多
+ async lingsheng(e) {
+ let msg = e.msg.replace(/#|铃声搜索/g, '')
+ let num = Math.ceil(Math.random() * 15)
+ if (num == 0) num = 1
+ let api = `http://xiaobai.klizi.cn/API/music/lingsheng.php?msg=${msg}&n=${num}`
+ let res = await fetch(api).then(res => res.json()).catch(err => logger.error(err))
+ if (!res) return e.reply(API_ERROR)
+ if (res.title == null && res.author == null) return e.reply('❎ 没有找到相关的歌曲哦~', true)
+
+ await e.reply([
+ `标题:${res.title}\n`,
+ `作者:${res.author}`
+ ])
+ await e.reply(await uploadRecord(res.aac, 0, false))
+ }
+
+ /** 半次元话题 */
+ async bcyTopic(e) {
+ let api = 'https://xiaobai.klizi.cn/API/other/bcy_topic.php'
+ let res = await fetch(api).then(res => res.json()).catch(err => logger.error(err))
+ if (!res) return e.reply(API_ERROR)
+ if (res.code != 200) return e.reply('❎ 出错辣' + JSON.stringify(res))
+ if (_.isEmpty(res.data)) return e.reply('请求错误!无数据,请稍后再试')
+ let msg = []
+ for (let i of res.data) {
+ if (!i.title || _.isEmpty(i.image)) continue
+ msg.push(i.title)
+ msg.push(i.image.map(item => segment.image(item)))
+ }
+ if (_.isEmpty(msg)) return this.bcyTopic(e)
+ common.getforwardMsg(e, msg)
+ }
+
+ // api大集合
+ async picture(e) {
+ let { sese, sesepro } = Config.getGroup(e.group_id)
+ if (!sese && !sesepro && !e.isMaster) return false
+ let key = 'yenai:apiAggregate:CD'
+ if (await redis.get(key)) return false
+
+ if (/jktj|接口统计/.test(e.msg)) {
+ let msg = ['现接口数量如下']
+ for (let i in picApis) {
+ if (i == 'mode') continue
+ let urls = picApis[i].url || picApis[i]
+ msg.push(`\n♡ ${i} => ${Array.isArray(urls) ? urls.length : 1}`)
+ }
+ return e.reply(msg)
+ }
+ // 解析消息中的类型
+ let regRet = apiReg.exec(e.msg)
+ if (regRet[1] == 'mode') return false
+ let picObj = picApis[_.sample(Object.keys(picApis).filter(item => new RegExp(item).test(regRet[1])))]
+ if (Array.isArray(picObj)) picObj = _.sample(picObj)
+ let urlReg = /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i
+ if (!picObj.url && !urlReg.test(encodeURI(picObj)) && !Array.isArray(picObj)) {
+ return logger.error(`${e.logFnc}未找到url`)
+ }
+
+ if (picObj.type !== 'image' && picObj.type !== 'text' && picObj.type !== 'json' && picObj.type) {
+ return logger.error(`${e.logFnc}类型不正确`)
+ }
+
+ let url = picObj.url || picObj
+ // 数组随机取或指定
+ if (Array.isArray(url)) url = _.sample(url)
+
+ url = encodeURI(url)
+
+ if (picObj.type == 'text') {
+ url = await fetch(url).then(res => res.text()).catch(err => logger.error(err))
+ } else if (picObj.type == 'json') {
+ if (!picObj.path) return logger.error(`${e.logFnc}json未指定路径`)
+ let res = await fetch(url).then(res => res.json()).catch(err => logger.error(err))
+ url = _.get(res, picObj.path)
+ }
+ if (!url) return logger.error(`${e.logFnc}未获取到图片链接`)
+
+ logger.debug(`${e.logFnc}使用接口:${url}`)
+ common.recallsendMsg(e, segment.image(url))
+ redis.set(key, 'cd', { EX: 2 })
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupAdmin.js b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupAdmin.js
new file mode 100644
index 0000000000000000000000000000000000000000..f9e80a96048cf0b0a5b36061137c0c4f56a4dfd5
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupAdmin.js
@@ -0,0 +1,717 @@
+import _ from 'lodash'
+import moment from 'moment'
+import { Config } from '../../components/index.js'
+import { common, GroupAdmin as Ga, puppeteer, QQApi, GroupBannedWords } from '../../model/index.js'
+import cronValidate from '../../tools/cronValidate.js'
+import { Time_unit } from '../../constants/other.js'
+// API请求错误文案
+const API_ERROR = '❎ 出错辣,请稍后重试'
+// 正则
+const Numreg = '[零一壹二两三四五六七八九十百千万亿\\d]+'
+const TimeUnitReg = Object.keys(Time_unit).join('|')
+
+/** 清理多久没发言的人正则 */
+const noactivereg = new RegExp(`^#(查看|清理|确认清理|获取)(${Numreg})个?(${TimeUnitReg})没发言的人(第(${Numreg})页)?$`)
+/** 我要自闭正则 */
+const Autisticreg = new RegExp(`^#?我要(自闭|禅定)(${Numreg})?个?(${TimeUnitReg})?$`, 'i')
+// 获取定时任务
+const redisTask = await Ga.getRedisMuteTask() || false
+export class GroupAdmin extends plugin {
+ constructor () {
+ super({
+ name: '椰奶群管',
+ event: 'message.group',
+ priority: 500,
+ rule: [
+ {
+ reg: `^#禁言\\s?((\\d+)\\s)?(${Numreg})?(${TimeUnitReg})?$`,
+ fnc: 'muteMember'
+ },
+ {
+ reg: '^#解禁(\\d+)?$',
+ fnc: 'noMuteMember'
+ },
+ {
+ reg: '^#全体(禁言|解禁)$',
+ fnc: 'muteAll'
+ },
+ {
+ reg: '^#踢(\\d+)?$',
+ fnc: 'kickMember'
+ },
+ {
+ reg: '^#(设置|取消)管理(\\d+)?$',
+ fnc: 'SetAdmin'
+ },
+ {
+ reg: '^#(允许|禁止|开启|关闭)匿名$',
+ fnc: 'AllowAnony'
+ },
+ {
+ reg: '^#发群公告',
+ fnc: 'AddAnnounce'
+ },
+ {
+ reg: '^#删群公告(\\d+)$',
+ fnc: 'DelAnnounce'
+ },
+ {
+ reg: '^#查群公告$',
+ fnc: 'GetAnnounce'
+ },
+ {
+ reg: '^#修改头衔',
+ fnc: 'adminsetTitle'
+ },
+ {
+ reg: '^#申请头衔',
+ fnc: 'SetGroupSpecialTitle'
+ },
+ {
+ reg: '^#(查)?(幸运)?字符(列表)?$',
+ fnc: 'qun_luckylist'
+ },
+ {
+ reg: '^#抽(幸运)?字符$',
+ fnc: 'qun_lucky'
+ },
+ {
+ reg: '^#替换(幸运)?字符(\\d+)$',
+ fnc: 'qun_luckyuse'
+ },
+ {
+ reg: '^#(开启|关闭)(幸运)?字符$',
+ fnc: 'qun_luckyset'
+ },
+ {
+ reg: '^#(获取|查看)?禁言列表$',
+ fnc: 'Mutelist'
+ },
+ {
+ reg: '^#解除全部禁言$',
+ fnc: 'relieveAllMute'
+ },
+ {
+ reg: `^#(查看|(确认)?清理)从未发言过?的人(第(${Numreg})页)?$`,
+ fnc: 'neverspeak'
+ },
+ {
+ reg: `^#(查看|获取)?(不活跃|潜水)排行榜(${Numreg})?$`,
+ fnc: 'RankingList'
+ },
+ {
+ reg: `^#(查看|获取)?最近的?入群(情况|记录)(${Numreg})?$`,
+ fnc: 'RankingList'
+ },
+ {
+ reg: noactivereg, // 清理多久没发言的人
+ fnc: 'noactive'
+ },
+ {
+ reg: '^#发通知',
+ fnc: 'Send_notice'
+ },
+ {
+ reg: '^#(设置)?定时(禁言|解禁)(.*)$|^#定时禁言任务$|^#取消定时(禁言|解禁)$',
+ fnc: 'timeMute'
+ },
+ {
+ reg: '^#(查看|获取)?群?发言(榜单|排行)((7|七)天)?',
+ fnc: 'SpeakRank'
+ },
+ {
+ reg: '^#?(谁|哪个吊毛|哪个屌毛|哪个叼毛)是龙王$',
+ fnc: 'dragonKing'
+ },
+ {
+ reg: '^#群星级$',
+ fnc: 'Group_xj'
+ },
+ {
+ reg: '^#群数据((7|七)天)?$',
+ fnc: 'groupData'
+ },
+ {
+ reg: '^#今日打卡$',
+ fnc: 'DaySigned'
+ },
+ {
+ reg: Autisticreg, // 我要自闭
+ fnc: 'Autistic'
+ },
+ {
+ reg: '^#((今|昨|前|明|后)天|\\d{4}-\\d{1,2}-\\d{1,2})谁生日$',
+ fnc: 'groupBirthday'
+ },
+ {
+ reg: '^#?(开启|关闭)加群通知$',
+ fnc: 'handleGroupAdd'
+ },
+ {
+ reg: '^#?(加|设|移)精$',
+ fnc: 'essenceMessage'
+ }
+ ]
+ })
+ this.task = redisTask
+ }
+
+ get Bot () {
+ return this.e.bot ?? Bot
+ }
+
+ /** 禁言 */
+ async muteMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ let reg = `#禁言\\s?((\\d+)\\s)?(${Numreg})?(${TimeUnitReg})?`
+ let regRet = e.msg.match(new RegExp(reg))
+ const time = common.translateChinaNum(regRet[3])
+ new Ga(e).muteMember(
+ e.group_id, qq ?? regRet[2], e.user_id, time, regRet[4]
+ ).then(res => e.reply(res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 解禁 */
+ async noMuteMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ let regRet = e.msg.match(/#解禁(\d+)/)
+ new Ga(e).muteMember(
+ e.group_id, qq ?? regRet[1], e.user_id, 0
+ ).then(res => e.reply(res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 全体禁言 */
+ async muteAll (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let type = /全体禁言/.test(e.msg)
+ let res = await e.group.muteAll(type)
+ if (!res) return e.reply('❎ 未知错误', true)
+ type ? e.reply('全都不准说话了哦~') : e.reply('好耶!!可以说话啦~')
+ }
+
+ // 踢群员
+ async kickMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ if (!qq) qq = e.msg.replace(/#|踢/g, '').trim()
+ new Ga(e).kickMember(e.group_id, qq, e.user_id)
+ .then(res => e.reply(res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 我要自闭
+ async Autistic (e) {
+ // 判断是否有管理
+ if (!e.group.is_admin && !e.group.is_owner) return
+
+ if (e.isMaster) return e.reply('别自闭啦~~', true)
+ if (e.member.is_admin && !e.group.is_owner) return e.reply('别自闭啦~~', true)
+ // 解析正则
+ let regRet = Autisticreg.exec(e.msg)
+ // 获取数字
+ let TabooTime = common.translateChinaNum(regRet[2] || 5)
+
+ let Company = Time_unit[_.toUpper(regRet[3]) || '分']
+
+ await e.group.muteMember(e.user_id, TabooTime * Company)
+ e.reply('那我就不手下留情了~', true)
+ }
+
+ // 设置管理
+ async SetAdmin (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ let type = /设置管理/.test(e.msg)
+ if (!qq) qq = e.msg.replace(/#|(设置|取消)管理/g, '').trim()
+
+ if (!qq || !(/\d{5,}/.test(qq))) return e.reply('❎ 请输入正确的QQ号')
+ let Member = e.group.pickMember(Number(qq))
+ // 判断是否有这个人
+ if (!Member.info) return e.reply('❎ 这个群没有这个人哦~')
+
+ let res = await e.group.setAdmin(qq, type)
+ let name = Member.card || Member.nickname
+ if (!res) return e.reply('❎ 未知错误')
+ type ? e.reply(`已经把「${name}」设置为管理啦!!`) : e.reply(`「${name}」的管理已经被我吃掉啦~`)
+ }
+
+ // 匿名
+ async AllowAnony (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let type = /(允许|开启)匿名/.test(e.msg)
+ let res = await e.group.allowAnony(type)
+ if (!res) return e.reply('❎ 未知错误', true)
+ type ? e.reply('已把匿名开启了哦,可以藏起来了~') : e.reply('已关闭匿名,小贼们不准藏了~')
+ }
+
+ // 发群公告
+ async AddAnnounce (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ // 获取发送的内容
+ let msg = e.msg.replace(/#|发群公告/g, '').trim()
+ if (!msg) return e.reply('❎ 公告不能为空')
+
+ let result = await new QQApi(e).setAnnounce(e.group_id, msg)
+
+ if (!result) return e.reply(API_ERROR)
+ if (result.ec != 0) {
+ e.reply('❎ 发送失败\n' + JSON.stringify(result, null, '\t'))
+ }
+ }
+
+ // 查群公告
+ async GetAnnounce (e) {
+ let res = await new QQApi(e).getAnnouncelist(e.group_id)
+ if (!res) return e.reply(API_ERROR)
+ return e.reply(res)
+ }
+
+ // 删群公告
+ async DelAnnounce (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let msg = e.msg.replace(/#|删群公告/, '').trim()
+ if (!msg) return e.reply('❎ 序号不可为空')
+
+ let result = await new QQApi(e).delAnnounce(e.group_id, msg)
+ if (!result) return e.reply(API_ERROR)
+
+ if (result.ec == 0) {
+ e.reply(`✅ 已删除「${result.text}」`)
+ } else {
+ e.reply('❎ 删除失败\n' + JSON.stringify(result, null, '\t'))
+ }
+ }
+
+ // 修改头衔
+ async adminsetTitle (e) {
+ if (!common.checkPermission(e, 'master', 'owner')) return
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ if (!qq) return e.reply('请艾特要修改的人哦~')
+ let text = e.msg.replace(/#?修改头衔/g, '')
+ let res = await e.group.setTitle(qq, text)
+ if (res) {
+ e.reply(`已经把这个小可爱的头衔设置为「${text}」辣`)
+ } else {
+ e.reply('额...没给上不知道发生了神魔')
+ }
+ }
+
+ // 申请头衔
+ async SetGroupSpecialTitle (e) {
+ if (!common.checkPermission(e, 'all', 'owner')) return
+
+ let Title = e.msg.replace(/#|申请头衔/g, '')
+ // 屏蔽词处理
+ let TitleFilterModeChange = GroupBannedWords.getTitleFilterModeChange(e.group_id)
+ let TitleBannedWords = GroupBannedWords.getTitleBannedWords(e.group_id)
+ TitleBannedWords = _.compact(TitleBannedWords)
+ if (!e.isMaster && !_.isEmpty(TitleBannedWords)) {
+ if (TitleFilterModeChange) {
+ let reg = new RegExp(TitleBannedWords.join('|'))
+ if (reg.test(Title)) return e.reply('这里面有不好的词汇哦~', true)
+ } else {
+ if (TitleBannedWords.includes(Title)) return e.reply('这是有不好的词汇哦~', true)
+ }
+ }
+ let res = await e.group.setTitle(e.user_id, Title)
+ if (!res) return e.reply('❎ 未知错误', true)
+
+ if (!Title) return e.reply('什么"(º Д º*)!没有头衔,哼把你的头衔吃掉!!!', true)
+
+ e.reply(`已将你的头衔更换为「${Title}」`, true)
+ }
+
+ // 字符列表
+ async qun_luckylist (e) {
+ let data = await new QQApi(e).luckylist(e.group_id)
+ if (!data) return e.reply(API_ERROR)
+ if (data.retcode != 0) return e.reply('❎ 获取数据失败\n' + JSON.stringify(data))
+
+ let msg = data.data.word_list.map((item, index) => {
+ let { wording, word_id, word_desc } = item.word_info
+ return `${word_id}:${wording}\n寓意:${word_desc}`
+ }).join('\n')
+ e.reply(msg)
+ }
+
+ // 抽幸运字符
+ async qun_lucky (e) {
+ let res = await new QQApi(e).drawLucky(e.group_id)
+
+ if (!res) return e.reply(API_ERROR)
+ if (res.retcode == 11004) return e.reply('今天已经抽过辣,明天再来抽取吧')
+ if (res.retcode != 0) return e.reply('❎ 错误\n' + JSON.stringify(res.data))
+
+ if (res.data.word_info) {
+ let { wording, word_desc } = res.data.word_info.word_info
+ e.reply(`恭喜您抽中了${wording}\n寓意为:${word_desc}`)
+ } else {
+ e.reply('恭喜您抽了中了个寂寞')
+ }
+ }
+
+ // 替换幸运字符
+ async qun_luckyuse (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let id = e.msg.replace(/#|替换(幸运)?字符/g, '')
+ let res = await new QQApi(e).equipLucky(e.group_id, id)
+
+ if (!res) return e.reply(API_ERROR)
+ if (res.retcode != 0) return e.reply('❎替换失败\n' + JSON.stringify(res))
+ e.reply('✅ OK')
+ }
+
+ // 开启或关闭群字符
+ async qun_luckyset (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let res = await new QQApi(e).swichLucky(e.group_id, /开启/.test(e.msg))
+ if (!res) return e.reply(API_ERROR)
+
+ if (res.retcode == 11111) return e.reply('❎ 重复开启或关闭')
+ if (res.retcode != 0) return e.reply('❎ 错误\n' + JSON.stringify(res))
+ e.reply('✅ OK')
+ }
+
+ // 获取禁言列表
+ async Mutelist (e) {
+ new Ga(e).getMuteList(e.group_id, true)
+ .then(res => common.getforwardMsg(e, res, {
+ isxml: true,
+ xmlTitle: '禁言列表'
+ }))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 解除全部禁言
+ async relieveAllMute (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ new Ga(e).releaseAllMute()
+ .then(() => e.reply('已经把全部的禁言解除辣╮( •́ω•̀)╭'))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 查看和清理多久没发言的人
+ async noactive (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ let regRet = noactivereg.exec(e.msg)
+ regRet[2] = common.translateChinaNum(regRet[2] || 1)
+ // 确认清理直接执行
+ if (regRet[1] == '确认清理') {
+ try {
+ return common.getforwardMsg(e,
+ await new Ga(e).clearNoactive(
+ e.group_id,
+ regRet[2],
+ regRet[3]
+ )
+ )
+ } catch (error) {
+ return common.handleException(e, error)
+ }
+ }
+ // 查看和清理都会发送列表
+ let page = common.translateChinaNum(regRet[5] || 1)
+ let msg = null
+ try {
+ msg = await new Ga(e).getNoactiveInfo(
+ e.group_id, regRet[2], regRet[3], page
+ )
+ } catch (err) {
+ return common.handleException(e, err)
+ }
+ // 清理
+ if (regRet[1] == '清理') {
+ let list = await new Ga(e).noactiveList(e.group_id, regRet[2], regRet[3])
+ e.reply([
+ `本次共需清理「${list.length}」人,防止误触发\n`,
+ `请发送:#确认清理${regRet[2]}${regRet[3]}没发言的人`
+ ])
+ }
+ common.getforwardMsg(e, msg, {
+ isxml: true,
+ xmlTitle: e.msg.replace(/#|查看|清理/g, '')
+ })
+ }
+
+ // 查看和清理从未发言的人
+ async neverspeak (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let list = null
+ try {
+ list = await new Ga(e).getNeverSpeak(e.group_id)
+ } catch (error) {
+ return common.handleException(e, error)
+ }
+
+ // 确认清理直接执行
+ if (/^#?确认清理/.test(e.msg)) {
+ e.reply('我要开始清理了哦,这可能需要一点时间٩(๑•ㅂ•)۶')
+ let arr = list.map(item => item.user_id)
+ let msg = await new Ga(e).BatchKickMember(e.group_id, arr)
+ return common.getforwardMsg(e, msg)
+ }
+ // 清理
+ if (/^#?清理/.test(e.msg)) {
+ e.reply([
+ `本次共需清理「${list.length}」人,防止误触发\n`,
+ '请发送:#确认清理从未发言的人'
+ ])
+ }
+ // 发送列表
+ let page = e.msg.match(new RegExp(Numreg))
+ page = page ? common.translateChinaNum(page[0]) : 1
+ new Ga(e).getNeverSpeakInfo(e.group_id, page)
+ .then(res => common.getforwardMsg(e, res, {
+ isxml: true,
+ xmlTitle: e.msg.replace(/#|查看|清理/g, '')
+ }))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 查看不活跃排行榜和入群记录
+ async RankingList (e) {
+ let num = e.msg.match(new RegExp(Numreg))
+ num = num ? common.translateChinaNum(num[0]) : 10
+ let msg = ''
+ if (/(不活跃|潜水)/.test(e.msg)) {
+ msg = await new Ga(e).InactiveRanking(e.group_id, num)
+ } else {
+ msg = await new Ga(e).getRecentlyJoined(e.group_id, num)
+ }
+ common.getforwardMsg(e, msg, { isxml: true })
+ }
+
+ // 发送通知
+ async Send_notice (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+
+ e.message[0].text = e.message[0].text.replace('#发通知', '').trim()
+ if (!e.message[0].text) e.message.shift()
+ if (_.isEmpty(e.message)) return e.reply('❎ 通知不能为空')
+ e.message.unshift(segment.at('all'))
+ e.reply(e.message)
+ }
+
+ // 设置定时群禁言
+ async timeMute (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+ let type = /禁言/.test(e.msg)
+ if (/任务/.test(e.msg)) {
+ let task = new Ga(e).getMuteTask()
+ if (!task.length) return e.reply('目前还没有定时禁言任务')
+ return common.getforwardMsg(e, task)
+ }
+ if (/取消/.test(e.msg)) {
+ new Ga(e).delMuteTask(e.group_id, type)
+ return e.reply(`已取消本群定时${type ? '禁言' : '解禁'}`)
+ }
+
+ let RegRet = e.msg.match(/定时(禁言|解禁)((\d{1,2})(:|:)(\d{1,2})|.*)/)
+ if (!RegRet || !RegRet[2]) return e.reply(`格式不对\n示范:#定时${type ? '禁言' : '解禁'}00:00 或 #定时${type ? '禁言' : '解禁'} + cron表达式`)
+ let cron = ''
+ if (RegRet[3] && RegRet[5]) {
+ cron = `0 ${RegRet[5]} ${RegRet[3]} * * ?`
+ } else {
+ cron = RegRet[2]
+ // 校验cron表达式
+ let Validate = cronValidate(cron.trim())
+ if (Validate !== true) return e.reply(Validate)
+ }
+
+ let res = await new Ga(e).setMuteTask(e.group_id, cron, type, e.self_id ?? Bot.uin)
+
+ res
+ ? e.reply('✅设置定时禁言成功,可发【#定时禁言任务】查看')
+ : e.reply(`❎ 该群定时${type ? '禁言' : '解禁'}已存在不可重复设置`)
+ }
+
+ // 谁是龙王
+ async dragonKing (e) {
+ // 浏览器截图
+ let screenshot = await puppeteer.Webpage({
+ url: `https://qun.qq.com/interactive/honorlist?gc=${e.group_id}&type=1&_wv=3&_wwv=129`,
+ headers: { Cookie: this.Bot.cookies['qun.qq.com'] },
+ font: true
+ })
+ if (screenshot) return e.reply(screenshot)
+ // 数据版
+ let res = await new QQApi(e).dragon(e.group_id)
+ if (!res) return e.reply(API_ERROR)
+ e.reply([
+ `本群龙王:${res.nick}`,
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${res.uin}`),
+ `蝉联天数:${res.avatar_size}`
+ ])
+ }
+
+ /** 群星级 */
+ async Group_xj (e) {
+ let screenshot = await puppeteer.Webpage({
+ url: `https://qqweb.qq.com/m/business/qunlevel/index.html?gc=${e.group_id}&from=0&_wv=1027`,
+ cookie: common.getck('qun.qq.com', this.Bot, true),
+ emulate: 'QQTheme',
+ font: true
+ })
+ if (screenshot) return e.reply(screenshot)
+ // 出错后发送数据
+ let result = await new QQApi(e).getCreditLevelInfo(e.group_id)
+ if (!result) return e.reply(API_ERROR)
+ if (result.ec != 0) return e.reply('❎ 查询错误\n' + JSON.stringify(result))
+ let { uiGroupLevel, group_name, group_uin } = result.info
+ let str = '⭐'
+ str = str.repeat(uiGroupLevel)
+ e.reply([
+ `群名:${group_name}\n`,
+ `群号:${group_uin}\n`,
+ `群星级:${str}`
+ ])
+ }
+
+ // 群发言榜单
+ async SpeakRank (e) {
+ if (!common.checkPermission(e, 'all', 'admin')) return
+
+ // 图片截图
+ let screenshot = await puppeteer.Webpage({
+ url: `https://qun.qq.com/m/qun/activedata/speaking.html?gc=${e.group_id}&time=${/(7|七)天/.test(e.msg) ? 1 : 0}`,
+ headers: { Cookie: this.Bot.cookies['qun.qq.com'] },
+ font: true
+ })
+ if (screenshot) return e.reply(screenshot)
+ // 出错后发送文字数据
+ let res = await new QQApi(e).SpeakRank(e.group_id, /(7|七)天/.test(e.msg))
+ if (!res) return e.reply(API_ERROR)
+ if (res.retcode != 0) return e.reply('❎ 未知错误\n' + JSON.stringify(res))
+ let msg = _.take(res.data.speakRank.map((item, index) =>
+ `${index + 1}:${item.nickname}-${item.uin}\n连续活跃${item.active}天:发言${item.msgCount}次`
+ ), 10).join('\n')
+ e.reply(msg)
+ }
+
+ // 今日打卡
+ async DaySigned (e) {
+ // 浏览器截图
+ let screenshot = await puppeteer.Webpage({
+ url: `https://qun.qq.com/v2/signin/list?gc=${e.group_id}`,
+ emulate: 'iPhone 6',
+ cookie: common.getck('qun.qq.com', this.Bot, true),
+ font: true
+ })
+ if (screenshot) return e.reply(screenshot)
+ // 出错后使用接口
+ let res = await new QQApi(e).signInToday(e.group_id)
+ if (!res) return e.reply(API_ERROR)
+ if (res.retCode != 0) return e.reply('❎ 未知错误\n' + JSON.stringify(res))
+
+ let list = res.response.page[0]
+ if (list.total == 0) return e.reply('今天还没有人打卡哦( ̄▽ ̄)"')
+ // 发送消息
+ let msg = list.infos.map((item, index) => `${index + 1}:${item.uidGroupNick}-${item.uid}\n打卡时间:${moment(item.signedTimeStamp * 1000).format('YYYY-MM-DD HH:mm:ss')}`).join('\n')
+ e.reply(msg)
+ }
+
+ // 查看某天谁生日
+ async groupBirthday (e) {
+ let date = e.msg.match(/^#?(今天|昨天|明天|后天|\d{4}-\d{1,2}-\d{1,2})谁生日$/)[1]
+ if (date == '昨天') {
+ date = moment().subtract(1, 'days').format('YYYY-MM-DD')
+ } else if (date == '前天') {
+ date = moment().subtract(2, 'days').format('YYYY-MM-DD')
+ } else if (date == '明天') {
+ date = moment().add(1, 'days').format('YYYY-MM-DD')
+ } else if (date == '后天') {
+ date = moment().add(2, 'days').format('YYYY-MM-DD')
+ } else if (date == '今天') {
+ date = moment().format('YYYY-MM-DD')
+ }
+ e.reply(
+ await puppeteer.Webpage({
+ url: `https://qun.qq.com/qqweb/m/qun/calendar/detail.html?_wv=1031&_bid=2340&src=3&gc=${e.group_id}&type=2&date=${date}`,
+ cookie: common.getck('qun.qq.com', this.Bot, true),
+ emulate: 'iPhone 6',
+ font: true
+ })
+ )
+ }
+
+ // 群数据
+ async groupData (e) {
+ if (!common.checkPermission(e, 'all', 'admin')) return
+
+ // 浏览器截图
+ let screenshot = await puppeteer.Webpage({
+ url: `https://qun.qq.com/m/qun/activedata/active.html?_wv=3&_wwv=128&gc=${e.group_id}&src=2`,
+ cookie: common.getck('qun.qq.com', this.Bot, true),
+ click: /(7|七)天/.test(e.msg)
+ ? [
+ {
+ selector: '#app > div.tabbar > div.tabbar__time > div.tabbar__time__date',
+ time: 500
+ },
+ {
+ selector: '#app > div.tabbar > div.tabbar__date-selector > div > div:nth-child(3)',
+ time: 1000
+ }
+ ]
+ : false,
+ font: true
+ })
+ if (screenshot) return e.reply(screenshot)
+ // 数据
+ let res = await new QQApi(e).groupData(e.group_id, /(7|七)天/.test(e.msg))
+ if (!res) return e.reply(API_ERROR)
+ if (res.retcode != 0) return e.reply(res.msg || JSON.stringify(res))
+ let { groupInfo, activeData, msgInfo, joinData, exitData, applyData } = res.data
+ e.reply(
+ [
+ `${groupInfo.groupName}(${groupInfo.groupCode})${/(7|七)天/.test(e.msg) ? '七天' : '昨天'}的群数据\n`,
+ '------------消息条数---------\n',
+ `消息条数:${msgInfo.total}\n`,
+ '------------活跃人数---------\n',
+ `活跃人数:${activeData.activeData}\n`,
+ `总人数:${activeData.groupMember}\n`,
+ `活跃比例:${activeData.ratio}%\n`,
+ '-----------加退群人数--------\n',
+ `申请人数:${joinData.total}\n`,
+ `入群人数:${applyData.total}\n`,
+ `退群人数:${exitData.total}\n`
+ ]
+ )
+ }
+
+ /** 开启或关闭加群通知 */
+ async handleGroupAdd (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+ let type = /开启/.test(e.msg) ? 'add' : 'del'
+ let isopen = Config.groupAdd.openGroup.includes(e.group_id)
+ if (isopen && type == 'add') return e.reply('❎ 本群加群申请通知已处于开启状态')
+ if (!isopen && type == 'del') return e.reply('❎ 本群暂未开启加群申请通知')
+ Config.modifyarr('groupAdd', 'openGroup', e.group_id, type)
+ e.reply(`✅ 已${type == 'add' ? '开启' : '关闭'}「${e.group_id}」的加群申请通知`)
+ }
+
+ /** 加精 */
+ async essenceMessage (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+ if (!e.source) return e.reply('请对要加精的消息进行引用')
+ let source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ let isAdd = e.msg.match(/加|设|移/)?.[0]
+ let res
+ if (isAdd == '加' || isAdd == '设') {
+ res = await this.Bot.setEssenceMessage(source.message_id)
+ } else {
+ res = await this.Bot.removeEssenceMessage(source.message_id)
+ }
+ e.reply(res || `${isAdd}精失败`)
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupBannedWords.js b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupBannedWords.js
new file mode 100644
index 0000000000000000000000000000000000000000..af65814b913feb2d0d8098863162f4c28f86143e
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupBannedWords.js
@@ -0,0 +1,281 @@
+import { common, GroupBannedWords } from '../../model/index.js'
+import _ from 'lodash'
+
+export class NewGroupBannedWords extends plugin {
+ constructor () {
+ super({
+ name: '椰奶群违禁词',
+ event: 'message.group',
+ priority: 1,
+ rule: [
+ {
+ reg: '^#?新增(模糊|精确|正则)?(踢|禁|撤|踢撤|禁撤)?违禁词',
+ fnc: 'add'
+ },
+ {
+ reg: '^#?删除违禁词',
+ fnc: 'del'
+ },
+ {
+ reg: '^#?查看违禁词',
+ fnc: 'query'
+ },
+ {
+ reg: '',
+ fnc: 'monitor',
+ log: false
+ },
+ {
+ reg: '^#?违禁词列表$',
+ fnc: 'list'
+ },
+ {
+ reg: '^#?设置违禁词禁言时间(\\d+)$',
+ fnc: 'muteTime'
+ },
+ {
+ reg: '^#(增加|减少|查看)头衔屏蔽词',
+ fnc: 'ProhibitedTitle'
+ },
+ {
+ reg: '^#切换头衔屏蔽词匹配(模式)?$',
+ fnc: 'ProhibitedTitlePattern'
+ }
+ ]
+
+ })
+ }
+
+ async monitor (e) {
+ if (!e.message || e.isMaster || e.member.is_owner || e.member.is_admin) {
+ return false
+ }
+ const groupBannedWords = GroupBannedWords.initTextArr(e.group_id)
+ if (_.isEmpty(groupBannedWords)) {
+ return false
+ }
+ const KeyWord = e.toString()
+ .replace(/#|#/g, '')
+ .replace(`{at:${Bot.uin}}`, '')
+ .trim()
+ const trimmedKeyWord = this.#trimAlias(KeyWord)
+ let data = null
+ for (const [k, v] of groupBannedWords) {
+ if (k.test(trimmedKeyWord)) {
+ data = v
+ break
+ }
+ }
+ if (!data) return false
+ const muteTime = GroupBannedWords.getMuteTime(e.group_id)
+ const punishments = {
+ 1: () => e.member.kick(),
+ 2: () => this.#mute(muteTime),
+ 3: () => e.recall(),
+ 4: () => {
+ e.member.kick()
+ e.recall()
+ },
+ 5: () => {
+ this.#mute(muteTime)
+ e.recall()
+ }
+ }
+ const groupPenaltyAction = {
+ 1: '踢出群聊',
+ 2: `禁言${muteTime}秒`,
+ 3: '撤回消息',
+ 4: '踢出群聊并撤回消息',
+ 5: `禁言${muteTime}秒并撤回消息`
+ }
+ if (punishments[data.penaltyType]) {
+ punishments[data.penaltyType]()
+ const keyWordTran = await GroupBannedWords.keyWordTran(data.rawItem)
+ const senderCard = e.sender.card || e.sender.nickname
+ const wordNum = keyWordTran.length - 2
+ const replaceWord = '*'.repeat(wordNum < 0 ? 0 : wordNum)
+ const bannedWord = keyWordTran.substr(0, 2) + replaceWord
+ e.reply([
+ `触发违禁词:${bannedWord}\n`,
+ `触发者:${senderCard}(${e.user_id})\n`,
+ `执行:${groupPenaltyAction[data.penaltyType]}`
+ ], false, { recallMsg: 30 })
+ }
+ }
+
+ /** 禁言 */
+ #mute (time) {
+ const e = this.e
+ if (e.anonymous) {
+ e.group.muteAnony(e.anonymous.flag, time)
+ } else {
+ e.member.mute(time)
+ }
+ }
+
+ /** 过滤别名 */
+ #trimAlias (msg) {
+ let groupCfg = this.e.runtime.cfg.getGroup(this.group_id)
+ let alias = groupCfg.botAlias
+ if (!Array.isArray(alias)) {
+ alias = [alias]
+ }
+ for (let name of alias) {
+ if (msg.startsWith(name)) {
+ msg = _.trimStart(msg, name).trim()
+ }
+ }
+
+ return msg
+ }
+
+ async add (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return false
+ let word = this.#trimAlias(e.toString())
+ word = word.match(/^#?新增(模糊|精确|正则)?(踢|禁|撤|踢撤|禁撤)?违禁词(.*)$/)
+ if (!word[3]) return e.reply('需要添加的屏蔽词为空')
+ // 校验正则
+ if (word[1] === '正则') {
+ try {
+ global.eval(word[3])
+ } catch {
+ return e.reply('正则表达式错误')
+ }
+ }
+ try {
+ let res = GroupBannedWords.addBannedWords(
+ e.group_id, word[3].trim(), word[1], word[2], e.user_id
+ )
+ e.reply([
+ '✅ 成功添加违禁词\n',
+ '违禁词:',
+ await res.words,
+ `\n匹配模式:${res.matchType}\n`,
+ `处理方式:${res.penaltyType}`
+ ])
+ } catch (error) {
+ common.handleException(e, error)
+ }
+ }
+
+ async del (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return false
+ let word = this.#trimAlias(e.toString())
+ word = word.replace(/#?删除违禁词/, '').trim()
+ if (!word) return e.reply('需要删除的屏蔽词为空')
+ try {
+ let msg = await GroupBannedWords.delBannedWords(e.group_id, word)
+ e.reply(['✅ 成功删除:', msg])
+ } catch (error) {
+ common.handleException(e, error)
+ }
+ }
+
+ async query (e) {
+ let word = this.#trimAlias(e.toString())
+ word = word.replace(/#?查看违禁词/, '').trim()
+ if (!word) return e.reply('需要查询的屏蔽词为空')
+ try {
+ const { words, matchType, penaltyType, addedBy, date } = GroupBannedWords.queryBannedWords(e.group_id, word)
+ e.reply([
+ '✅ 查询违禁词\n',
+ '违禁词:',
+ await words,
+ `\n匹配模式:${matchType}\n`,
+ `处理方式:${penaltyType}\n`,
+ `添加人:${addedBy ?? '未知'}\n`,
+ `添加时间:${date ?? '未知'}`
+ ])
+ } catch (error) {
+ common.handleException(e, error)
+ }
+ }
+
+ async list (e) {
+ const groupBannedWords = GroupBannedWords.initTextArr(e.group_id)
+ if (_.isEmpty(groupBannedWords)) {
+ return e.reply('❎ 没有违禁词')
+ }
+ const msg = []
+ for (const [, v] of groupBannedWords) {
+ const { matchType, penaltyType, addedBy, date, rawItem } = v
+ msg.push([
+ '违禁词:',
+ await GroupBannedWords.keyWordTran(rawItem),
+ `\n匹配模式:${GroupBannedWords.matchTypeMap[matchType]}\n`,
+ `处理方式:${GroupBannedWords.penaltyTypeMap[penaltyType]}\n`,
+ `添加人:${addedBy ?? '未知'}\n`,
+ `添加时间:${date ?? '未知'}`
+ ])
+ }
+ common.getforwardMsg(e, msg)
+ }
+
+ async muteTime (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return false
+ let time = e.msg.match(/\d+/)[0]
+ GroupBannedWords.setMuteTime(e.group_id, time)
+ e.reply(`✅ 群${e.group_id}违禁词禁言时间已设置为${time}s`)
+ }
+
+ // 增删查头衔屏蔽词
+ async ProhibitedTitle (e) {
+ // 获取现有的头衔屏蔽词
+ let shieldingWords = GroupBannedWords.getTitleBannedWords(e.group_id)
+ // 判断是否需要查看头衔屏蔽词
+ if (/查看/.test(e.msg)) {
+ // 返回已有的头衔屏蔽词列表
+ return e.reply(`现有的头衔屏蔽词如下:${shieldingWords.join('\n')}`)
+ }
+ if (!common.checkPermission(e, 'admin', 'admin')) return false
+ // 获取用户输入的要增加或删除的屏蔽词
+ let message = e.msg.replace(/#|(增加|减少)头衔屏蔽词/g, '').trim().split(',')
+ // 判断用户是要增加还是删除屏蔽词
+ let isAddition = /增加/.test(e.msg)
+ let existingWords = []
+ let newWords = []
+
+ // 遍历用户输入的屏蔽词,区分已有和新的屏蔽词
+ for (let word of message) {
+ if (shieldingWords.includes(word)) {
+ existingWords.push(word)
+ } else {
+ newWords.push(word)
+ }
+ }
+
+ // 去重
+ existingWords = _.compact(_.uniq(existingWords))
+ newWords = _.compact(_.uniq(newWords))
+
+ // 判断是要增加还是删除屏蔽词
+ if (isAddition) {
+ // 添加新的屏蔽词
+ if (!_.isEmpty(newWords)) {
+ GroupBannedWords.addTitleBannedWords(e.group_id, newWords)
+ e.reply(`✅ 成功添加:${newWords.join(',')}`)
+ }
+ // 提示已有的屏蔽词
+ if (!_.isEmpty(existingWords)) {
+ e.reply(`❎ 以下词已存在:${existingWords.join(',')}`)
+ }
+ } else {
+ // 删除已有的屏蔽词
+ if (!_.isEmpty(existingWords)) {
+ GroupBannedWords.delTitleBannedWords(e.group_id, existingWords)
+ e.reply(`✅ 成功删除:${existingWords.join(',')}`)
+ }
+ // 提示不在屏蔽词中的词
+ if (!_.isEmpty(newWords)) {
+ e.reply(`❎ 以下词未在屏蔽词中:${newWords.join(',')}`)
+ }
+ }
+ }
+
+ // 修改头衔匹配模式
+ async ProhibitedTitlePattern (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return false
+ let res = GroupBannedWords.setTitleFilterModeChange(e.group_id)
+ e.reply(`✅ 已修改匹配模式为${res ? '精确' : '模糊'}匹配`)
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupVerify.js b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupVerify.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb99116e945b861b504be4f5ef3afb7f64216862
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/groupVerify.js
@@ -0,0 +1,256 @@
+import { Config } from '../../components/index.js'
+import { common, GroupAdmin as Ga } from '../../model/index.js'
+import _ from 'lodash'
+// 全局
+let temp = {}
+const ops = ['+', '-']
+export class NewGroupVerify extends plugin {
+ constructor () {
+ super({
+ name: '椰奶入群验证',
+ dsc: '重新验证和绕过验证',
+ event: 'message.group',
+ priority: 5,
+ rule: [
+ {
+ reg: '^#重新验证(\\d+|从未发言的人)?$',
+ fnc: 'cmdReverify'
+ },
+ {
+ reg: '^#绕过验证(\\d+)?$',
+ fnc: 'cmdPass'
+ },
+ {
+ reg: '^#(开启|关闭)验证$',
+ fnc: 'handelverify'
+ },
+ {
+ reg: '^#切换验证模式$',
+ fnc: 'setmode'
+ },
+ {
+ reg: '^#设置验证超时时间(\\d+)(s|秒)?$',
+ fnc: 'setovertime'
+ }
+ ]
+ })
+ this.verifycfg = Config.groupverify
+ }
+
+ // 重新验证
+ async cmdReverify (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+
+ if (!this.verifycfg.openGroup.includes(e.group_id)) return e.reply('当前群未开启验证哦~', true)
+
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ if (!qq) qq = e.msg.replace(/#|重新验证/g, '').trim()
+
+ if (qq == '从未发言的人') return this.cmdReverifyNeverSpeak(e)
+
+ if (!(/\d{5,}/.test(qq))) return e.reply('❎ 请输入正确的QQ号')
+ qq = Number(qq)
+ if (qq == (e.bot ?? Bot).uin) return
+
+ if (Config.masterQQ.includes(qq)) return e.reply('❎ 该命令对机器人管理员无效')
+
+ if (temp[qq + e.group_id]) return e.reply('❎ 目标群成员处于验证状态')
+
+ await verify(qq, e.group_id, e)
+ }
+
+ // 绕过验证
+ async cmdPass (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+
+ if (!this.verifycfg.openGroup.includes(e.group_id)) return e.reply('当前群未开启验证哦~', true)
+
+ let qq = e.message.find(item => item.type == 'at')?.qq
+ if (!qq) qq = e.msg.replace(/#|绕过验证/g, '').trim()
+
+ if (!(/\d{5,}/.test(qq))) return e.reply('❎ 请输入正确的QQ号')
+
+ if (qq == (e.bot ?? Bot).uin) return
+ qq = Number(qq)
+ if (!temp[qq + e.group_id]) return e.reply('❎ 目标群成员当前无需验证')
+
+ clearTimeout(temp[qq + e.group_id].kickTimer)
+
+ clearTimeout(temp[qq + e.group_id].remindTimer)
+
+ delete temp[qq + e.group_id]
+
+ return await e.reply(this.verifycfg.SuccessMsgs[e.group_id] || this.verifycfg.SuccessMsgs[0] || '✅ 验证成功,欢迎入群')
+ }
+
+ async cmdReverifyNeverSpeak (e) {
+ let list = null
+ try {
+ list = await new Ga(e).getNeverSpeak(e.group_id)
+ } catch (error) {
+ return common.handleException(e, error)
+ }
+ for (let item of list) {
+ await verify(item.user_id, e.group_id, e)
+ await common.sleep(2000)
+ }
+ }
+
+ // 开启验证
+ async handelverify (e) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+ let type = /开启/.test(e.msg) ? 'add' : 'del'
+ let isopen = this.verifycfg.openGroup.includes(e.group_id)
+ if (isopen && type == 'add') return e.reply('❎ 本群验证已处于开启状态')
+ if (!isopen && type == 'del') return e.reply('❎ 本群暂未开启验证')
+ Config.modifyarr('groupverify', 'openGroup', e.group_id, type)
+ e.reply(`✅ 已${type == 'add' ? '开启' : '关闭'}本群验证`)
+ }
+
+ // 切换验证模式
+ async setmode (e) {
+ if (!common.checkPermission(e, 'master')) return
+ let value = this.verifycfg.mode == '模糊' ? '精确' : '模糊'
+ Config.modify('groupverify', 'mode', value)
+ e.reply(`✅ 已切换验证模式为${value}验证`)
+ }
+
+ // 设置验证超时时间
+ async setovertime (e) {
+ if (!common.checkPermission(e, 'master')) return
+ let overtime = e.msg.match(/\d+/g)
+ Config.modify('groupverify', 'time', Number(overtime))
+ e.reply(`✅ 已将验证超时时间设置为${overtime}秒`)
+ if (overtime < 60) {
+ e.reply('建议至少一分钟(60秒)哦ε(*´・ω・)з')
+ }
+ }
+}
+
+// 进群监听
+Bot.on?.('notice.group.increase', async (e) => {
+ logger.mark(`[Yenai-Plugin][进群验证]收到${e.user_id}的进群事件`)
+ let { openGroup, DelayTime } = Config.groupverify
+
+ if (!openGroup.includes(e.group_id)) return
+ if (!e.group.is_admin && !e.group.is_owner) return
+ if (e.user_id == (e.bot ?? Bot).uin) return
+ if (Config.masterQQ.includes(e.user_id)) return
+
+ await common.sleep(DelayTime * 1000)
+ await verify(e.user_id, e.group_id, e)
+})
+
+// 答案监听
+Bot.on?.('message.group', async (e) => {
+ let { openGroup, mode, SuccessMsgs } = Config.groupverify
+
+ if (!openGroup.includes(e.group_id)) return
+
+ if (!e.group.is_admin && !e.group.is_owner) return
+
+ if (!temp[e.user_id + e.group_id]) return
+
+ const { verifyCode, kickTimer, remindTimer } = temp[e.user_id + e.group_id]
+
+ const { nums, operator } = temp[e.user_id + e.group_id]
+
+ const isAccurateModeOK = mode === '精确' && e.raw_message == verifyCode
+
+ const isVagueModeOK = mode === '模糊' && e.raw_message?.includes(verifyCode)
+
+ const isOK = isAccurateModeOK || isVagueModeOK
+
+ if (isOK) {
+ delete temp[e.user_id + e.group_id]
+ clearTimeout(kickTimer)
+ clearTimeout(remindTimer)
+ return await e.reply(SuccessMsgs[e.group_id] || SuccessMsgs[0] || '✅ 验证成功,欢迎入群')
+ } else {
+ temp[e.user_id + e.group_id].remainTimes -= 1
+
+ const { remainTimes } = temp[e.user_id + e.group_id]
+
+ if (remainTimes > 0) {
+ await e.recall()
+
+ const msg = `\n❎ 验证失败\n你还有「${remainTimes}」次机会\n请发送「${nums[0]} ${operator} ${nums[1]}」的运算结果`
+ return await e.reply([segment.at(e.user_id), msg])
+ }
+ clearTimeout(kickTimer)
+ clearTimeout(remindTimer)
+ await e.reply([segment.at(e.user_id), '\n验证失败,请重新申请'])
+ delete temp[e.user_id + e.group_id]
+ return await e.group.kickMember(e.user_id)
+ }
+})
+
+// 主动退群
+Bot.on?.('notice.group.decrease', async (e) => {
+ if (!e.group.is_admin && !e.group.is_owner) return
+
+ if (!temp[e.user_id + e.group_id]) return
+
+ clearTimeout(temp[e.user_id + e.group_id].kickTimer)
+
+ clearTimeout(temp[e.user_id + e.group_id].remindTimer)
+
+ delete temp[e.user_id + e.group_id]
+
+ e.group.sendMsg(`「${e.user_id}」主动退群,验证流程结束`)
+})
+
+// 发送验证信息
+async function verify (user_id, group_id, e) {
+ if (!e.group.is_admin && !e.group.is_owner) return
+ user_id = Number(user_id)
+ group_id = Number(group_id)
+ logger.mark(`[Yenai-Plugin][进群验证]进行${user_id}的验证`)
+
+ const { times, range, time, remindAtLastMinute } = Config.groupverify
+ const operator = ops[_.random(0, 1)]
+
+ let [m, n] = [_.random(range.min, range.max), _.random(range.min, range.max)]
+ while (m == n) {
+ n = Math.floor(Math.random() * (range.max - range.min + 1)) + range.min
+ }
+
+ [m, n] = [m >= n ? m : n, m >= n ? n : m]
+
+ const verifyCode = String(operator === '-' ? m - n : m + n)
+ logger.mark(`[Yenai-Plugin][进群验证]答案:${verifyCode}`)
+ const kickTimer = setTimeout(async () => {
+ e.reply([segment.at(user_id), '\n验证超时,移出群聊,请重新申请'])
+
+ delete temp[user_id + group_id]
+
+ clearTimeout(kickTimer)
+
+ return await e.group.kickMember(user_id)
+ }, time * 1000)
+
+ const shouldRemind = remindAtLastMinute && time >= 120
+
+ const remindTimer = setTimeout(async () => {
+ if (shouldRemind && temp[user_id + group_id].remindTimer) {
+ const msg = ` \n验证仅剩最后一分钟\n请发送「${m} ${operator} ${n}」的运算结果\n否则将会被移出群聊`
+
+ await e.reply([segment.at(user_id), msg])
+ }
+ clearTimeout(remindTimer)
+ }, Math.abs(time * 1000 - 60000))
+
+ const msg = ` 欢迎!\n请在「${time}」秒内发送\n「${m} ${operator} ${n}」的运算结果\n否则将会被移出群聊`
+
+ // 消息发送成功才写入
+ if (await e.reply([segment.at(user_id), msg])) {
+ temp[user_id + group_id] = {
+ remainTimes: times,
+ nums: [m, n],
+ operator,
+ verifyCode,
+ kickTimer,
+ remindTimer
+ }
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/apps/groupAdmin/privateGroupAdmin.js b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/privateGroupAdmin.js
new file mode 100644
index 0000000000000000000000000000000000000000..f95a033a6bb952be3ab29c0f3bf92d7b64d4a1d3
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/groupAdmin/privateGroupAdmin.js
@@ -0,0 +1,63 @@
+import { GroupAdmin as Ga, common } from '../../model/index.js'
+import { Time_unit } from '../../constants/other.js'
+// 正则
+const Numreg = '[一壹二两三四五六七八九十百千万亿\\d]+'
+const TimeUnitReg = Object.keys(Time_unit).join('|')
+const muteMemberReg = new RegExp(`^#禁言\\s?(\\d+)\\s(\\d+)\\s(${Numreg})?(${TimeUnitReg})?$`)
+export class PrivateGroupAdmin extends plugin {
+ constructor () {
+ super({
+ name: '椰奶私聊群管',
+ event: 'message',
+ priority: 2000,
+ rule: [
+ {
+ reg: muteMemberReg,
+ fnc: 'muteMember'
+ },
+ {
+ reg: '^#解禁\\s?(\\d+)\\s(\\d+)$',
+ fnc: 'nomuteMember'
+ },
+ {
+ reg: '^#全体(禁言|解禁)(\\d+)$',
+ fnc: 'muteAll'
+ },
+ {
+ reg: '^#踢\\s?(\\d+)\\s(\\d+)$',
+ fnc: 'kickMember'
+ }
+ ]
+ })
+ }
+
+ async muteMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = e.msg.match(muteMemberReg)
+ const time = common.translateChinaNum(regRet[3])
+ let res = await new Ga(e).muteMember(regRet[1], regRet[2], e.user_id, time, regRet[4])
+ e.reply(res)
+ }
+
+ async noMuteMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = e.msg.match(/^#解禁\s?(\d+)\s(\d+)$/)
+ let res = await new Ga(e).muteMember(regRet[1], regRet[2], e.user_id, 0)
+ e.reply(res)
+ }
+
+ async muteAll (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = e.msg.match(/全体(禁言|解禁)(\d+)/)
+ let group = (e.bot ?? Bot).pickGroup(Number(regRet[2]))
+ group.muteAll(regRet[1] == '禁言')
+ e.reply(`✅ 已将群「${group.name}(${group.group_id})」${regRet[1] == '禁言' ? '开启' : '解除'}全体禁言`)
+ }
+
+ async kickMember (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ let regRet = e.msg.match(/#踢\s?(\d+)\s(\d+)$/)
+ let res = await Ga.kickMember(regRet[1], regRet[2], e.user_id)
+ e.reply(res)
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/handle.js b/Yunzai/plugins/yenai-plugin/apps/handle.js
new file mode 100644
index 0000000000000000000000000000000000000000..14169f363d002f19178a28cb5cdc89ad2c0ae805
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/handle.js
@@ -0,0 +1,429 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import _ from 'lodash'
+import { common } from '../model/index.js'
+import moment from 'moment'
+const ROLE_MAP = {
+ admin: '群管理',
+ owner: '群主',
+ member: '群员'
+}
+export class NewHandle extends plugin {
+ constructor () {
+ super({
+ name: '椰奶申请处理',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: '^#?(同意|拒绝)$',
+ fnc: 'Handle'
+ },
+ {
+ reg: '^#?回复',
+ fnc: 'Replys',
+ event: 'message.private'
+ },
+ {
+ reg: '^#?(同意|拒绝|查看)(全部)?好友申请(\\d+)?$',
+ fnc: 'PrivateAdd'
+ },
+ {
+ reg: '^#?(加为|添加)好友$',
+ fnc: 'addFriend',
+ event: 'message.private'
+ },
+ {
+ reg: '^#?(同意|拒绝|查看)(全部)?(加|入)?群申请(\\d+)?$',
+ fnc: 'GroupAdd',
+ event: 'message.group'
+ },
+ {
+ reg: '^#?(同意|拒绝|查看)(全部)?群邀请(\\d+)?$',
+ fnc: 'GroupInvite'
+ },
+ {
+ reg: '^#?查看全部请求$',
+ fnc: 'SystemMsgAll'
+ }
+ ]
+ })
+ }
+
+ /** 同意拒绝好友申请 */
+ async PrivateAdd (e) {
+ if (!e.isMaster) return false
+ let yes = !!/同意/.test(e.msg)
+
+ const systemMsg = (await (e.bot ?? Bot).getSystemMsg());
+ const FriendAdd = systemMsg.filter(
+ item => item.request_type == 'friend' &&
+ (item.sub_type === 'add' || item.sub_type === 'single')
+ );
+
+ if (_.isEmpty(FriendAdd)) return e.reply('暂无好友申请(。-ω-)zzz', true)
+
+ if (/查看好友申请/.test(e.msg)) {
+ FriendAdd = FriendAdd.map((item) => {
+ return [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\n申请人QQ:${item.user_id}\n`,
+ `申请人昵称:${item.nickname}\n`,
+ `申请来源:${item.source || '未知'}\n`,
+ `申请时间:${moment(item.time * 1000).format('YYYY-MM-DD HH:mm:ss')}\n`,
+ `附加信息:${item.comment || '无附加信息'}`
+ ]
+ })
+ let msg = [
+ `现有未处理的好友申请如下,共${FriendAdd.length}条`,
+ '可用"#同意好友申请"或"#拒绝好友申请"进行处理',
+ ...FriendAdd
+ ]
+ return common.getforwardMsg(e, msg)
+ } else if (/全部/.test(e.msg)) {
+ // 同意全部好友申请
+ await e.reply('好哒,我开始处理辣٩(๑•ㅂ•)۶')
+ let success = []; let fail = []
+ for (let i of FriendAdd) {
+ logger.mark(`${e.logFnc}${yes ? '同意' : '拒绝'}${i.user_id}的好友申请`)
+ let res = await i.approve(yes)
+ if (res) {
+ success.push(`${success.length + 1}、${i.user_id}`)
+ } else {
+ fail.push(`${fail.length + 1}、${i.user_id}`)
+ }
+ await common.sleep(2000)
+ }
+ let msg = [
+ `本次共${yes ? '同意' : '拒绝'}${FriendAdd.length}条好友申请\n成功:${success.length}\n失败:${fail.length}`
+ ]
+ if (!_.isEmpty(success)) msg.push(['以下为成功的名单:\n', success.join('\n')])
+ if (!_.isEmpty(fail)) msg.push(['以下为失败的名单:\n', fail.join('\n')])
+
+ return common.getforwardMsg(e, msg)
+ } else {
+ // 处理单个好友申请
+ let qq = e.msg.replace(/#|(同意|拒绝)好友申请/g, '').trim()
+ if (!qq) return e.reply('❎ 请输入正确的QQ')
+
+ let member = FriendAdd.find(item => item.user_id == qq)
+ if (_.isEmpty(member)) return e.reply('❎ 没有找到这个人的好友申请')
+
+ let result = member.approve(yes)
+ if (result) {
+ e.reply(`✅ 已${yes ? '同意' : '拒绝'}${member.nickname}(${qq})的好友申请`)
+ } else {
+ e.reply('❎ 未知错误')
+ }
+ }
+ }
+
+ /** 引用同意好友申请和群邀请 */
+ async Handle (e) {
+ if (!e.source) return false
+ if (e.source.user_id != (e.bot ?? Bot).uin) return false
+ let yes = !!/同意/.test(e.msg)
+ let source
+ if (e.isGroup) {
+ source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ } else {
+ source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ }
+ if (!source) return e.reply('❎ 获取消息失败')
+ let sourceMsg = source.raw_message?.split('\n')
+ if (!sourceMsg) return e.reply('❎ 获取原消息失败,请使用"同意xxx"进行处理')
+ if (e.isGroup) {
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+
+ let source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ let yes = /同意/.test(e.msg)
+ logger.mark(`${e.logFnc}${yes ? '同意' : '拒绝'}加群通知`)
+ let userId = await redis.get(`yenai:groupAdd:${source.message_id}`)
+ if (!userId) return e.reply('找不到原消息了,手动同意叭~')
+
+ let member = (await (e.bot ?? Bot).getSystemMsg())
+ .find(item => item.request_type == 'group' && item.sub_type == 'add' && item.group_id == e.group_id && item.user_id == userId)
+
+ if (_.isEmpty(member)) return e.reply('呜呜呜,没找到这个淫的加群申请(つд⊂)')
+
+ if (/风险/.test(member.tips)) return e.reply('该账号为风险账号请手动处理哦ಠ~ಠ')
+
+ if (await member.approve(yes)) {
+ e.reply(`已${yes ? '同意' : '拒绝'}${member.nickname}(${member.user_id})的加群申请辣٩(๑^o^๑)۶`)
+ } else {
+ e.reply('呜呜呜,处理失败辣(இωஇ)')
+ }
+ return true
+ } else {
+ if (!e.isMaster) return false
+ if (/添加好友申请/.test(sourceMsg[0])) {
+ let qq = sourceMsg[1].match(/[1-9]\d*/g)
+ if ((e.bot ?? Bot).fl.get(Number(qq))) return e.reply('❎ 已经同意过该申请了哦~')
+
+ logger.mark(`${e.logFnc}${yes ? '同意' : '拒绝'}好友申请`)
+
+ await (e.bot ?? Bot).pickFriend(qq)
+ .setFriendReq('', yes)
+ .then(() => e.reply(`✅ 已${yes ? '同意' : '拒绝'}${qq}的好友申请`))
+ .catch(() => e.reply('❎ 请检查是否已同意该申请'))
+ } else if (/邀请机器人进群/.test(sourceMsg[0])) {
+ let groupid = sourceMsg[1].match(/[1-9]\d*/g)
+ if ((e.bot ?? Bot).fl.get(Number(groupid))) { return e.reply('❎ 已经同意过该申请了哦~') }
+
+ let qq = sourceMsg[3].match(/[1-9]\d*/g)
+ let seq = sourceMsg[6].match(/[1-9]\d*/g)
+
+ logger.mark(`${e.logFnc}${yes ? '同意' : '拒绝'}群邀请`);
+
+ (e.bot ?? Bot).pickUser(qq)
+ .setGroupInvite(groupid, seq, yes)
+ .then(() => e.reply(`✅ 已${yes ? '同意' : '拒绝'}${qq}的群邀请`))
+ .catch(() => e.reply('❎ 请检查是否已同意该邀请'))
+ } else if (/加群申请/.test(sourceMsg[0])) {
+ let groupId = sourceMsg[1].match(/\d+/g)
+ let qq = sourceMsg[3].match(/\d+/g)
+
+ let member = (await (e.bot ?? Bot).getSystemMsg()).find(item => item.sub_type == 'add' && item.group_id == groupId && item.user_id == qq)
+ if (_.isEmpty(member)) return e.reply('没有找到这个人的加群申请哦')
+
+ let result = member.approve(yes)
+ if (result) {
+ e.reply(`已${yes ? '同意' : '拒绝'}${member.nickname}(${qq})的加群申请`)
+ } else {
+ e.reply('失败了,可能为风险账号请手动处理')
+ }
+ } else {
+ return false
+ }
+ }
+ }
+
+ // 回复好友消息
+ async Replys (e) {
+ if (!e.isMaster) return false
+ let qq = ''
+ let group = ''
+ let msgs = e.message[0].text.split(' ')
+ if (e.source) {
+ let source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ let res
+ try {
+ res = source.raw_message.split('\n')
+ } catch {
+ return e.reply('❎ 消息可能已过期')
+ }
+ if (/好友消息/.test(res[0]) && /好友账号/.test(res[1])) {
+ qq = res[1].match(/[1-9]\d*/g)
+ } else if (/群临时消息/.test(res[0])) {
+ qq = res[2].match(/[1-9]\d*/g)
+ group = res[1].match(/[1-9]\d*/g)
+ } else {
+ return e.reply('❎ 请检查是否引用正确')
+ }
+ e.message[0].text = e.message[0].text.replace(/#|回复/g, '').trim()
+ } else {
+ if (msgs.length == 1 && !/\d/.test(msgs[0])) {
+ return e.reply('❎ QQ号不能为空')
+ } else if (/\d/.test(msgs[0])) {
+ qq = msgs[0].match(/[1-9]\d*/g)
+ e.message[0].text = msgs.slice(1).join(' ')
+ } else {
+ qq = msgs[1]
+ e.message[0].text = msgs.slice(2).join(' ')
+ }
+ }
+ if (!e.message[0].text) e.message.shift()
+
+ if (e.message.length === 0) return e.reply('❎ 消息不能为空')
+ if (group) {
+ logger.mark(`${e.logFnc}回复临时消息`)
+ return (e.bot ?? Bot).sendTempMsg(group, qq, e.message)
+ .then(() => { e.reply('✅ 已把消息发给它了哦~') })
+ .catch((err) => common.handleException(e, err, { MsgTemplate: '❎ 发送失败\n错误信息为:{error}' }))
+ }
+
+ if (!/^\d+$/.test(qq)) return e.reply('❎ QQ号不正确,人家做不到的啦>_<~')
+
+ if (!(e.bot ?? Bot).fl.get(Number(qq))) return e.reply('❎ 好友列表查无此人')
+
+ logger.mark(`${e.logFnc}回复好友消息`);
+
+ (e.bot ?? Bot).pickFriend(qq)
+ .sendMsg(e.message)
+ .then(() => { e.reply('✅ 已把消息发给它了哦~') })
+ .catch((err) => common.handleException(e, err, { MsgTemplate: '❎ 发送失败\n错误信息为:{error}' }))
+ }
+
+ // 加群员为好友
+ async addFriend (e) {
+ if (!e.isMaster) return false
+ if (!e.source) return false
+ let source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ let msg = source.raw_message.split('\n')
+ if (!/临时消息/.test(msg[0]) || !/来源群号/.test(msg[1]) || !/发送人QQ/.test(msg[2])) return false
+ let group = msg[1].match(/\d+/g)
+ let qq = msg[2].match(/\d+/g)
+ if ((e.bot ?? Bot).fl.get(Number(qq))) return e.reply('❎ 已经有这个人的好友了哦~')
+ if (!(e.bot ?? Bot).gl.get(Number(group))) { return e.reply('❎ 群聊列表查无此群') }
+ logger.mark(`${e.logFnc}主动添加好友`);
+
+ (e.bot ?? Bot).addFriend(group, qq)
+ .then(() => e.reply(`✅ 已向${qq}发送了好友请求`))
+ .catch(() => e.reply('❎ 发送请求失败'))
+ }
+
+ // 入群请求
+ async GroupAdd (e) {
+ let SystemMsg = (await (e.bot ?? Bot).getSystemMsg())
+ .filter(item => item.request_type == 'group' && item.sub_type == 'add' && item.group_id == e.group_id)
+ if (_.isEmpty(SystemMsg)) return e.reply('暂无加群申请(。-ω-)zzz', true)
+ // 查看
+ if (/查看/.test(e.msg)) {
+ SystemMsg = SystemMsg.map(item => {
+ return [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\nQQ:${item.user_id}\n`,
+ `昵称:${item.nickname}\n`,
+ item.tips ? `Tips:${item.tips}\n` : '',
+ `${item.comment}`
+ ]
+ })
+ let msg = [
+ `现有未处理的加群申请如下,总共${SystemMsg.length}条`,
+ '可使用 "#(同意|拒绝)加群申请xxx"\n或 "#(同意|拒绝)全部加群申请"',
+ ...SystemMsg
+ ]
+ return common.getforwardMsg(e, msg)
+ }
+ if (!common.checkPermission(e, 'admin', 'admin')) return
+ let yes = /同意/.test(e.msg)
+
+ if (/全部/.test(e.msg)) {
+ e.reply('好哒,我开始处理辣٩(๑•ㅂ•)۶')
+ let success = []; let fail = []; let risk = []
+ for (let i of SystemMsg) {
+ if (await i.approve(yes)) {
+ success.push(`${success.length + 1}、${i.user_id}`)
+ } else {
+ if (/风险/.test(i.tips)) {
+ risk.push(`${risk.length + 1}、${i.user_id}`)
+ } else {
+ fail.push(`${fail.length + 1}、${i.user_id}`)
+ }
+ }
+ await common.sleep(1000)
+ }
+ let msg = [
+ `本次共处理${SystemMsg.length}条群申请\n成功:${success.length}\n失败:${fail.length}\n风险:${risk.length}`
+ ]
+ if (!_.isEmpty(success)) msg.push(['以下为成功的名单:\n', success.join('\n')])
+ if (!_.isEmpty(fail)) msg.push(['以下为失败的名单:\n', fail.join('\n')])
+ if (!_.isEmpty(risk)) msg.push(['以下为风险账号名单:\n', risk.join('\n')])
+ common.getforwardMsg(e, msg)
+ } else {
+ let qq = e.msg.replace(/#(同意|拒绝)(加|入)群申请/g, '').trim()
+
+ if (!qq) return e.reply('QQ号呢,QQ号呢d(ŐдŐ๑)', true)
+
+ let member = SystemMsg.find(item => item.user_id == qq)
+
+ if (_.isEmpty(member)) return e.reply('呜呜呜,没找到这个淫的加群申请(つд⊂)')
+
+ if (/风险/.test(member.tips)) return e.reply('该账号为风险账号请手动处理哦ಠ~ಠ')
+
+ if (await member.approve(yes)) {
+ e.reply(`已${yes ? '同意' : '拒绝'}${member.nickname}(${member.user_id})的加群申请辣٩(๑^o^๑)۶`)
+ } else {
+ e.reply('呜呜呜,处理失败辣(இωஇ)')
+ }
+ }
+ }
+
+ // 群邀请列表
+ async GroupInvite (e) {
+ if (!e.isMaster) return false
+ let SystemMsg = (await (e.bot ?? Bot).getSystemMsg()).filter(item => item.request_type == 'group' && item.sub_type == 'invite')
+ if (_.isEmpty(SystemMsg)) return e.reply('暂无群邀请哦(。-ω-)zzz', true)
+ let yes = /同意/.test(e.msg)
+ // 查看
+ if (/查看/.test(e.msg)) {
+ SystemMsg = SystemMsg.map(item => {
+ return [
+ segment.image(`https://p.qlogo.cn/gh/${item.group_id}/${item.group_id}/100`),
+ `\n邀请群号:${item.group_id}\n`,
+ `邀请群名:${item.group_name}\n`,
+ `邀请人QQ:${item.user_id}\n`,
+ `邀请人昵称:${item.nickname}\n`,
+ `邀请人身份:${ROLE_MAP[item.role]}`
+ ]
+ })
+ let msg = [
+ `现有未处理的群邀请如下,总共${SystemMsg.length}条`,
+ '可使用 "#(同意|拒绝)群邀请xxx"\n或 "#(同意|拒绝)全部群邀请"',
+ ...SystemMsg
+ ]
+ return common.getforwardMsg(e, msg)
+ } else if (/全部/.test(e.msg)) {
+ e.reply('好哒,我开始处理辣٩(๑•ㅂ•)۶')
+ let success = []; let fail = []
+ for (let i of SystemMsg) {
+ if (await i.approve(yes)) {
+ success.push(`${success.length + 1}、${i.user_id}`)
+ } else {
+ fail.push(`${fail.length + 1}、${i.user_id}`)
+ }
+ await common.sleep(1000)
+ }
+ let msg = [`本次共处理${SystemMsg.length}条群邀请\n成功:${success.length}\n失败:${fail.length}`]
+ if (!_.isEmpty(success)) msg.push(['以下为成功的名单:\n', success.join('\n')])
+ if (!_.isEmpty(fail)) msg.push(['以下为失败的名单:\n', fail.join('\n')])
+ common.getforwardMsg(e, msg)
+ } else {
+ let groupid = e.msg.replace(/#(同意|拒绝)群邀请/g, '').trim()
+
+ if (!groupid) return e.reply('群号呢,群号呢d(ŐдŐ๑)', true)
+
+ let Invite = SystemMsg.find(item => item.group_id == groupid)
+
+ if (_.isEmpty(Invite)) return e.reply('欸,你似不似傻哪有这个群邀请(O∆O)')
+
+ if (await Invite.approve(yes)) {
+ e.reply(`已${yes ? '同意' : '拒绝'}${Invite.group_id}这个群邀请辣٩(๑^o^๑)۶`)
+ } else {
+ e.reply('呜呜呜,处理失败辣(இωஇ)')
+ }
+ }
+ }
+
+ // 全部请求
+ async SystemMsgAll (e) {
+ if (!e.isMaster) return false
+ let SystemMsg = await (e.bot ?? Bot).getSystemMsg()
+ let FriendAdd = []; let onewayFriend = []; let GroupAdd = []; let GroupInvite = []
+ for (let i of SystemMsg) {
+ if (i.request_type == 'friend') {
+ if (i.sub_type == 'add') {
+ FriendAdd.push(i)
+ } else {
+ onewayFriend.push(i)
+ }
+ } else {
+ if (i.sub_type == 'add') {
+ GroupAdd.push(i)
+ } else {
+ GroupInvite.push(i)
+ }
+ }
+ }
+ let msg = []
+ if (!_.isEmpty(FriendAdd)) msg.push(`好友申请:${FriendAdd.length}条\n可使用"#查看好友申请" 查看详情`)
+ if (!_.isEmpty(GroupInvite)) msg.push(`群邀请:${GroupInvite.length}条\n可使用"#查看群邀请" 查看详情`)
+ if (!_.isEmpty(onewayFriend)) msg.push(`单向好友:${onewayFriend.length}条`)
+ if (e.isGroup) {
+ GroupAdd = GroupAdd.filter(item => item.group_id == e.group.id)
+ if (!_.isEmpty(GroupAdd)) msg.push(`当前群申请:${GroupAdd.length}条`)
+ }
+ if (_.isEmpty(msg)) return e.reply('好耶!!一条请求都没有哦o( ❛ᴗ❛ )o', true)
+ msg.unshift('以下为暂未处理的请求')
+ common.getforwardMsg(e, msg)
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/help.js b/Yunzai/plugins/yenai-plugin/apps/help.js
new file mode 100644
index 0000000000000000000000000000000000000000..81866f002c130f13eb2b8a869294cbf483f0651a
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/help.js
@@ -0,0 +1,93 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import fs from 'fs'
+import _ from 'lodash'
+import { Data } from '../components/index.js'
+import { puppeteer } from '../model/index.js'
+const helpType = {
+ 群管: 'gpAdmin',
+ 涩涩: 'sese'
+}
+const helpReg = new RegExp(
+ `^#?椰奶(插件)?(${Object.keys(helpType).join('|')})?(帮助|菜单|功能)$`
+)
+export class YenaiHelp extends plugin {
+ constructor () {
+ super({
+ name: '椰奶帮助',
+ event: 'message',
+ priority: 2000,
+ rule: [
+ {
+ reg: helpReg,
+ fnc: 'message'
+ }
+ ]
+ })
+ }
+
+ async message () {
+ return await help(this.e)
+ }
+}
+
+async function help (e) {
+ let custom = {}
+ // let help = {}
+ const special = e.msg.match(helpReg)[2]
+
+ let diyCfg, sysCfg
+ if (special) {
+ let gpAdminHelp = await Data.importCfg(helpType[special])
+ diyCfg = gpAdminHelp.diyCfg
+ sysCfg = gpAdminHelp.sysCfg
+ } else {
+ let indexHelp = await Data.importCfg('help')
+ diyCfg = indexHelp.diyCfg
+ sysCfg = indexHelp.sysCfg
+ }
+
+ // custom = help
+
+ let helpConfig = _.defaults(diyCfg.helpCfg || {}, custom.helpCfg, sysCfg.helpCfg)
+ let helpList = diyCfg.helpList || custom.helpList || sysCfg.helpList
+ let helpGroup = []
+
+ _.forEach(helpList, (group) => {
+ if (group.auth && group.auth === 'master' && !e.isMaster) {
+ return true
+ }
+
+ _.forEach(group.list, (help) => {
+ let icon = help.icon * 1
+ if (!icon) {
+ help.css = 'display:none'
+ } else {
+ let x = (icon - 1) % 10
+ let y = (icon - x - 1) / 10
+ help.css = `background-position:-${x * 50}px -${y * 50}px`
+ }
+ })
+
+ helpGroup.push(group)
+ })
+ return await puppeteer.render('help/index', {
+ helpCfg: helpConfig,
+ helpGroup,
+ bg: await rodom(),
+ colCount: 3,
+ element: 'default'
+ }, {
+ e,
+ scale: 1.2
+ })
+}
+
+const rodom = async function () {
+ let image = fs.readdirSync('./plugins/yenai-plugin/resources/help/imgs/')
+ let list_img = []
+ for (let val of image) {
+ list_img.push(val)
+ }
+ let imgs = list_img.length == 1 ? list_img[0] : list_img[_.random(0, list_img.length - 1)]
+ return imgs
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/nga.js b/Yunzai/plugins/yenai-plugin/apps/nga.js
new file mode 100644
index 0000000000000000000000000000000000000000..091436b19f9f8493adef149310f8add28bd13d68
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/nga.js
@@ -0,0 +1,107 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import gsCfg from '../../genshin/model/gsCfg.js'
+import fs from 'node:fs'
+import common from '../../../lib/common/common.js'
+import { Data, Plugin_Path } from '../components/index.js'
+import { incomeCurve } from '../constants/nga.js'
+
+export class NGA extends plugin {
+ constructor () {
+ super({
+ name: '椰奶NGA',
+ dsc: '收益曲线',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: '^#?(更新)?(.*)(收益曲线|参考面板)(帮助)?$',
+ fnc: 'NGA'
+ }
+ ]
+ })
+ this.incomeCurvePath = `${Plugin_Path}/temp/incomeCurve`
+ this.referencePanelPath = `${Plugin_Path}/temp/referencPanel`
+ this.incomeCurveObj = incomeCurve
+ }
+
+ // 初始化
+ async initFolder (type) {
+ Data.createDir(`data/${type == '收益曲线' ? 'incomeCurve' : 'referencPanel'}`)
+ }
+
+ async NGA () {
+ let role = {}
+ let regRet = this.e.msg.match('^#?(更新)?(.*)(收益曲线|参考面板)(帮助)?$')
+ if (regRet[4]) {
+ role.name = '帮助'
+ } else {
+ role = gsCfg.getRole(regRet[2])
+ }
+
+ if (!role) return logger.error(`${this.e.logFnc}未找到该角色`, role)
+
+ let type = regRet[3]
+ /** 主角特殊处理 */
+ if (['10000005', '10000007', '20000000'].includes(String(role.roleId))) {
+ if (!['风主', '岩主', '雷主', '草主'].includes(role.alias)) {
+ await this.e.reply(`请选择:风主${type}、岩主${type}、雷主${type}、草主${type}`)
+ return
+ } else {
+ role.name = role.alias
+ }
+ }
+
+ let imgList = []
+
+ if (type == '收益曲线') {
+ // 收益曲线
+ if (!this.incomeCurveObj[role.name]) {
+ return this.e.reply('暂时无该角色收益曲线~>_<')
+ }
+ let urls = this.incomeCurveObj[role.name]
+
+ if (Array.isArray(urls)) {
+ urls.forEach((item, index) => imgList.push({
+ url: item,
+ imgPath: `${this.incomeCurvePath}/${role.name}_${index + 1}.png`
+ }))
+ } else {
+ imgList.push({
+ url: urls,
+ imgPath: `${this.incomeCurvePath}/${role.name}.png`
+ })
+ }
+ } else {
+ // 参考面板
+ imgList.push({
+ url: `https://gitlab.com/yeyang52/referenc-profile/-/raw/master/image/${role.name}.png`,
+ imgPath: `${this.referencePanelPath}/${role.name}.png`
+ })
+ }
+
+ for (const item of imgList) {
+ // 检测图片并下载图片
+ if (!fs.existsSync(item.imgPath) || regRet[1]) {
+ this.initFolder(type)
+ await this.getImg(item.url, item.imgPath)
+ }
+ // 发送图片
+ if (fs.existsSync(item.imgPath)) {
+ await this.e.reply(segment.image(item.imgPath))
+ }
+ }
+ }
+
+ // 下载图片
+ async getImg (name, Path) {
+ logger.mark(`${this.e.logFnc} 下载${name}素材图`)
+
+ if (!await common.downFile(name, Path)) {
+ return false
+ }
+
+ logger.mark(`${this.e.logFnc} 下载${name}素材成功`)
+
+ return true
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/picSearch.js b/Yunzai/plugins/yenai-plugin/apps/picSearch.js
new file mode 100644
index 0000000000000000000000000000000000000000..3db701199c4a25315fbb5230eb6edd5e8ea6eeed
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/picSearch.js
@@ -0,0 +1,126 @@
+import { PicSearch, common } from '../model/index.js'
+import { Config } from '../components/index.js'
+import _ from 'lodash'
+export class NewPicSearch extends plugin {
+ constructor () {
+ super({
+ name: '椰奶图片搜索',
+ event: 'message',
+ priority: 2000,
+ rule: [
+ {
+ reg: '^#?(椰奶)?(以图)?搜图$',
+ fnc: 'SauceNAO'
+ },
+ {
+ reg: /^#?(SauceNAO|sn)搜图$/i,
+ fnc: 'SauceNAO'
+ },
+ {
+ reg: /^#?(椰奶|WhatAnime|wa)?(以图)?搜番$/i,
+ fnc: 'WhatAnime'
+ },
+ {
+ reg: /^#?(Ascii2D|ac)搜图$/i,
+ fnc: 'Ascii2D'
+ },
+ {
+ reg: /^#设置SauceNAOApiKey/i,
+ fnc: 'UploadSauceNAOKey'
+ }
+
+ ]
+ })
+ }
+
+ async SauceNAO (e) {
+ if (!await this._Authentication(e)) return
+ if (!await this.handelImg(e, 'SauceNAO')) return
+ await PicSearch.SauceNAO(e.img[0])
+ .then(async res => {
+ res.length == 1
+ ? common.recallsendMsg(e, res[0], true)
+ : common.recallSendForwardMsg(e, res, { xmlTitle: false })
+ })
+ .catch(async err => {
+ await common.handleException(e, err)
+ if (Config.picSearch.useAscii2dWhenFailed) {
+ await e.reply('SauceNAO搜图出错,自动使用Ascii2D进行搜索')
+ await this.Ascii2D(e)
+ }
+ })
+ }
+
+ async Ascii2D (e) {
+ if (!await this._Authentication(e)) return
+ if (!await this.handelImg(e, 'Ascii2D')) return
+ await PicSearch.Ascii2D(e.img[0])
+ .then(res => common.recallSendForwardMsg(e, [...res.color, ...res.bovw], { xmlTitle: false }))
+ .catch(err => common.handleException(e, err))
+ }
+
+ async WhatAnime (e) {
+ if (!await this._Authentication(e)) return
+ if (!await this.handelImg(e, 'WhatAnime')) return
+ await PicSearch.WhatAnime(e.img[0].replace('/c2cpicdw.qpic.cn/offpic_new/', '/gchat.qpic.cn/gchatpic_new/'))
+ .then(async res => {
+ for (let i of res) {
+ await e.reply(i)
+ }
+ })
+ .catch(err => common.handleException(e, err))
+ }
+
+ async UploadSauceNAOKey (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ if (e.isGroup) return e.reply('请私聊进行添加')
+ let apiKey = e.msg.replace(/#设置SauceNAOapiKey/i, '').trim()
+ if (!apiKey) return e.reply('❎ 请发送正确的apikey')
+ Config.modify('picSearch', 'SauceNAOApiKey', apiKey)
+ e.reply('OK')
+ }
+
+ async _Authentication (e) {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+ const { allowPM, limit, isMasterUse } = Config.picSearch
+ if (isMasterUse) {
+ e.reply('主人没有开放这个功能哦(*/ω\*)')
+ return false
+ }
+ if (!allowPM && !e.isGroup) {
+ e.reply('主人已禁用私聊该功能')
+ return false
+ }
+ if (!await common.limit(e.user_id, 'picSearch', limit)) {
+ e.reply('您已达今日「搜图搜番」次数上限', true, { at: true })
+ return false
+ }
+ return true
+ }
+
+ async handelImg (e, funName) {
+ if (e.source) {
+ let source
+ if (e.isGroup) {
+ source = (await e.group.getChatHistory(e.source.seq, 1)).pop()
+ } else {
+ source = (await e.friend.getChatHistory(e.source.time, 1)).pop()
+ }
+ e.img = [source.message.find(item => item.type == 'image')?.url]
+ }
+ if (!_.isEmpty(e.img)) return true
+ e.sourceFunName = funName
+ this.setContext('MonitorImg')
+ e.reply('⚠ 请发送图片')
+ return false
+ }
+
+ async MonitorImg () {
+ if (!this.e.img) {
+ this.e.reply('❎ 未检测到图片操作已取消')
+ } else {
+ this[this.getContext().MonitorImg.sourceFunName](this.e)
+ }
+ this.finish('MonitorImg')
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/pixiv.js b/Yunzai/plugins/yenai-plugin/apps/pixiv.js
new file mode 100644
index 0000000000000000000000000000000000000000..04f81be9c041e00099fefe18cb8706971a8ffc45
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/pixiv.js
@@ -0,0 +1,258 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import { Config } from '../components/index.js'
+import { Pixiv, common, setu } from '../model/index.js'
+import { Admin } from './admin.js'
+import { ImageRPSS } from '../constants/pixiv.js'
+// 文案
+const SWITCH_ERROR = '主人没有开放这个功能哦(*/ω\*)'
+// 汉字数字匹配正则
+const numReg = '[一壹二两三四五六七八九十百千万亿\\d]+'
+// 正则
+const pidReg = /^#?pid搜图\s?(\d+)$/i
+
+const rankingrReg = new RegExp(`^#?看看((\\d{4}-\\d{1,2}-\\d{1,2})的)?(${Object.keys(Pixiv.ranktype).join('|')})(r18)?榜\\s?(第(${numReg})页)?$`, 'i')
+const tagReg = new RegExp(`^#?tag(pro)?搜图(.*?)(第(${numReg})页)?$`, 'i')
+const uidReg = new RegExp(`^#?uid搜图(.*?)(第(${numReg})页)?$`, 'i')
+const searchUser = new RegExp(`^#?user搜索(.*?)(第(${numReg})页)?$`, 'i')
+const randomImgReg = new RegExp(`^#?来(${numReg})?张(好(康|看)(的|哒)|hkd|涩图)$|^#有内鬼$`)
+
+export class NewPixiv extends plugin {
+ constructor () {
+ super({
+ name: '椰奶pixiv',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: pidReg,
+ fnc: 'searchPid'
+ },
+ {
+ reg: rankingrReg,
+ fnc: 'pixivRank'
+ },
+ {
+ reg: tagReg,
+ fnc: 'searchTags'
+ },
+ {
+ reg: uidReg,
+ fnc: 'searchUid'
+ },
+ {
+ reg: searchUser,
+ fnc: 'searchUser'
+ },
+ {
+ reg: randomImgReg,
+ fnc: 'vilipixRandomImg'
+ },
+ {
+ reg: '^#?(查看|获取)?热门(t|T)(a|A)(g|G)$',
+ fnc: 'popularTags'
+ },
+ {
+ reg: '^#?看?看?相关作品(\\d+)$',
+ fnc: 'relatedIllust'
+ },
+ {
+ reg: '^#来(\\d+)?张推荐图$',
+ fnc: 'illustRecommended'
+ },
+ {
+ reg: '^#?(P|p)ximg(pro)?$',
+ fnc: 'pximg'
+ },
+ {
+ reg: '^#(p站|pixiv)(查看|更换)代理',
+ fnc: 'setProxy',
+ permission: 'master'
+ },
+ {
+ reg: '^#(p站|pixiv)(开启|关闭)直连$',
+ fnc: 'directConnection',
+ permission: 'master'
+ },
+ {
+ reg: '^#(p站|pixiv)登录信息$',
+ fnc: 'loginInfo',
+ permission: 'master'
+ }
+ ]
+ })
+ }
+
+ // pid搜图
+ async searchPid (e) {
+ if (!await this._Authentication(e, 'sese')) return
+ e.reply(Pixiv.startMsg)
+ let regRet = pidReg.exec(e.msg)
+ let filter = !e.isMaster && !setu.getR18(e.group_id)
+ await Pixiv.illust(regRet[1], filter)
+ .then(async res => {
+ await e.reply(res.msg)
+ res.img.length == 1 ? common.recallsendMsg(e, res.img) : common.recallSendForwardMsg(e, res.img, false)
+ })
+ .catch(err => common.handleException(e, err))
+ }
+
+ // p站排行榜
+ async pixivRank (e) {
+ let regRet = rankingrReg.exec(e.msg)
+ if (!await this._Authentication(e, 'sese')) return
+ if ((regRet[4] && !setu.getR18(e.group_id)) && !e.isMaster) {
+ return e.reply(SWITCH_ERROR)
+ }
+
+ e.reply(Pixiv.startMsg)
+
+ let page = common.translateChinaNum(regRet[6])
+ await Pixiv.Rank(page, regRet[2], regRet[3], regRet[4])
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 关键词搜图 */
+ async searchTags (e) {
+ let regRet = tagReg.exec(e.msg)
+ if (!await this._Authentication(e, 'sese')) return
+ if (regRet[1] && !await this._Authentication(e, 'sesepro')) return
+
+ e.reply(Pixiv.startMsg)
+
+ let page = common.translateChinaNum(regRet[4])
+ await Pixiv[`${regRet[1] ? 's' : 'vilipixS'}earchTags`](regRet[2], page, !setu.getR18(e.group_id))
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 获取热门tag */
+ async popularTags (e) {
+ if (!await this._Authentication(e, 'sese')) return
+ e.reply(Pixiv.startMsg)
+ await Pixiv.PopularTags()
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 以uid搜图**/
+ async searchUid (e) {
+ if (!await this._Authentication(e, 'sese')) return
+
+ e.reply(Pixiv.startMsg)
+
+ let regRet = uidReg.exec(e.msg)
+ let page = common.translateChinaNum(regRet[3])
+
+ await Pixiv.userIllust(regRet[1], page, !setu.getR18(e.group_id))
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 随机原创插画
+ async vilipixRandomImg (e) {
+ if (!await this._Authentication(e, 'sese')) return
+ e.reply(Pixiv.startMsg)
+ let regRet = randomImgReg.exec(e.msg)
+
+ let num = regRet[1] || 1
+ if (num > 50) {
+ e.reply('你要的太多辣,奴家只给你一张辣(•́へ•́ ╬)')
+ num = 1
+ }
+ num = common.translateChinaNum(num)
+ await Pixiv.vilipixRandomImg(num)
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // 相关作品
+ async relatedIllust (e) {
+ if (!await this._Authentication(e, 'sese')) return
+
+ e.reply(Pixiv.startMsg)
+
+ let regRet = e.msg.match(/\d+/)
+ await Pixiv.relatedIllust(regRet[0], !setu.getR18(e.group_id))
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // p站单图
+ async pximg (e) {
+ let ispro = /pro/.test(e.msg)
+ if (!await this._Authentication(e, 'sese')) return
+ if (ispro && !await this._Authentication(e, 'sesepro', false)) return
+
+ await Pixiv.pximg(ispro)
+ .then(res => ispro ? common.recallSendForwardMsg(e, [res]) : common.recallsendMsg(e, res, false, { anony: true }))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 搜索用户 */
+ async searchUser (e) {
+ if (!await this._Authentication(e, 'sese')) return
+
+ e.reply(Pixiv.startMsg)
+ let regRet = e.msg.match(searchUser)
+ let page = common.translateChinaNum(regRet[3])
+ await Pixiv.searchUser(regRet[1], page, !setu.getR18(e.group_id))
+ .then(res => common.recallSendForwardMsg(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ /** 推荐作品 */
+ async illustRecommended (e) {
+ if (!await this._Authentication(e, 'sese')) return
+ e.reply(Pixiv.startMsg)
+ let num = e.msg.match(/\d+/) || 1
+ await Pixiv.illustRecommended(num).then(res => {
+ res.length == 1
+ ? common.recallsendMsg(e, res[0], true)
+ : common.recallSendForwardMsg(e, res)
+ }).catch(err => common.handleException(e, err))
+ }
+
+ // 更换代理
+ async setProxy (e) {
+ if (/查看/.test(e.msg)) return e.reply(await redis.get('yenai:proxy'))
+ let proxy = e.msg.replace(/#|(p站|pixiv)更换代理/g, '').trim()
+ if (new RegExp(`^[1-${ImageRPSS.length}]$`).test(proxy)) {
+ proxy = ImageRPSS[proxy - 1]
+ }
+ if (!/([\w\d]+\.){2}[\w\d]+/.test(proxy)) {
+ return e.reply('请检查代理地址是否正确')
+ }
+ logger.mark(`${e.logFnc}切换为${proxy}`)
+ Config.modify('pixiv', 'pixivImageProxy', proxy)
+ new Admin().SeSe_Settings(e)
+ }
+
+ /** 图片直连 */
+ async directConnection (e) {
+ let isSwitch = /开启/.test(e.msg)
+ Config.modify('pixiv', 'pixivDirectConnection', isSwitch)
+ new Admin().SeSe_Settings(e)
+ }
+
+ /** 登录信息 */
+ async loginInfo (e) {
+ await Pixiv.loginInfo()
+ .then(res => e.reply(res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ async _Authentication (e, type = 'sese', limit = true) {
+ if (e.isMaster) return true
+ if (!Config.pixiv.allowPM && !e.isGroup) {
+ e.reply('主人已禁用私聊该功能')
+ return false
+ }
+ if (!common.checkSeSePermission(e, type)) return false
+ if (limit && !await common.limit(e.user_id, 'pixiv', Config.pixiv.limit)) {
+ e.reply('您已达今日「Pixiv」次数上限', true, { at: true })
+ return false
+ }
+ return true
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/search.js b/Yunzai/plugins/yenai-plugin/apps/search.js
new file mode 100644
index 0000000000000000000000000000000000000000..0298be8be50c53fd505384768f8cabdbf166c2f2
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/search.js
@@ -0,0 +1,61 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import _ from 'lodash'
+import { puppeteer, funApi } from '../model/index.js'
+import { SEARCH_MAP } from '../constants/search.js'
+import common from '../lib/common/common.js'
+const searchReg = new RegExp(`^#?(${_.keys(SEARCH_MAP).join('|')})搜索(.*)`)
+
+export class NewSearch extends plugin {
+ constructor () {
+ super({
+ name: '椰奶搜索',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: searchReg,
+ fnc: 'search'
+ },
+ {
+ reg: '^#?搜索菜单$',
+ fnc: 'help'
+ },
+ {
+ reg: '^#bgg搜索',
+ fnc: 'bggSearch'
+ },
+ {
+ reg: '^#bgg排行$',
+ fnc: 'bggRank'
+ }
+ ]
+
+ })
+ }
+
+ async help (e) {
+ const searchs = Object.keys(SEARCH_MAP)
+ const menu = '当前支持的搜索引擎:\n'
+ const tip = '\n格式:<搜索引擎> + 搜索 + <关键词>\n比如:萌娘百科搜索可莉'
+ return e.reply(menu + searchs.join('、') + tip)
+ }
+
+ async search (e) {
+ let regRet = searchReg.exec(e.msg)
+ if (/(lp|ip)|(i|p|l)(地址|查询)/ig.test(regRet[2])) return e.reply('(;`O´)o警告!!触发屏蔽词!!!', true)
+ let url = SEARCH_MAP[regRet[1]] + encodeURIComponent(regRet[2])
+ e.reply([await puppeteer.Webpage({ url }), url])
+ }
+
+ async bggSearch (e) {
+ let keyword = e.msg.replace(/#?bgg搜索/, '')
+ funApi.bgg(keyword)
+ .then(res => e.reply(res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ async bggRank (e) {
+ let url = 'https://boardgamegeek.com/browse/boardgame'
+ e.reply([await puppeteer.Webpage({ url }), url])
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/setu.js b/Yunzai/plugins/yenai-plugin/apps/setu.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2f8a372680ba70337df95c5f357ac116cde6d93
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/setu.js
@@ -0,0 +1,140 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import { Config } from '../components/index.js'
+import { setu, common } from '../model/index.js'
+import { Admin } from './admin.js'
+
+const NumReg = '[零一壹二两三四五六七八九十百千万亿\\d]+'
+
+export class SeSe extends plugin {
+ constructor () {
+ super({
+ name: '椰奶setu',
+ event: 'message',
+ priority: 500,
+ rule: [
+ {
+ reg: '^#椰奶tag(.*)$',
+ fnc: 'setuTag'
+ },
+ {
+ reg: `^#(setu|无内鬼)\\s?((${NumReg})张)?$`, // 无内鬼
+ fnc: 'setuRandom'
+ },
+ {
+ reg: `^#(撤回间隔|群(c|C)(d|D))(${NumReg})(s|秒)?$`,
+ fnc: 'setGroupRecallAndCD',
+ event: 'message.group',
+ permission: 'master'
+ },
+ {
+ reg: '^#(开启|关闭)(私聊)?涩涩$',
+ fnc: 'setSeSe',
+ permission: 'master'
+ },
+ {
+ reg: `^#?设置cd\\s?((\\d+)\\s)?(${NumReg})(s|秒)?$`, // 设置cd
+ fnc: 'setCd',
+ permission: 'master'
+ }
+ ]
+ })
+ }
+
+ async setuRandom (e) {
+ if (!await this._Authentication(e)) return
+
+ const cdTime = setu.getRemainingCd(e.user_id, e.group_id)
+
+ if (cdTime) return e.reply(` ${setu.CDMsg}你的CD还有${cdTime}`, false, { at: true })
+
+ let num = e.msg.match(new RegExp(NumReg))
+ num = num ? common.translateChinaNum(num[0]) : 1
+ if (num > 20) {
+ return e.reply('❎ 最大张数不能大于20张')
+ } else if (num > 6) {
+ e.reply('你先等等,你冲的有点多~')
+ }
+
+ // 开始执行
+ e.reply(setu.startMsg)
+
+ await setu.setuApi(setu.getR18(e.group_id), num)
+ .then(res => setu.sendMsgOrSetCd(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ // tag搜图
+ async setuTag (e) {
+ if (!await this._Authentication(e)) return
+
+ let cdTime = setu.getRemainingCd(e.user_id, e.group_id)
+ if (cdTime) return e.reply(` ${setu.CDMsg}你的CD还有${cdTime}`, false, { at: true })
+
+ let tag = e.msg.replace(/#|椰奶tag/g, '').trim()
+ let num = e.msg.match(new RegExp(`(${NumReg})张`))
+ if (!num) {
+ num = 1
+ } else {
+ tag = tag.replace(num[0], '').trim()
+ num = common.translateChinaNum(num[1])
+ }
+
+ if (num > 20) {
+ return e.reply('❎ 最大张数不能大于20张')
+ } else if (num > 6) {
+ e.reply('你先等等,你冲的有点多~')
+ } else {
+ e.reply(setu.startMsg)
+ }
+
+ if (!tag) return e.reply('tag为空!!!', false, { at: true })
+ tag = tag.split(' ')?.map(item => item.split('|'))
+ if (tag.length > 3) return e.reply('tag最多只能指定三个哦~', false, { at: true })
+
+ await setu.setuApi(setu.getR18(e.group_id), num, tag)
+ .then(res => setu.sendMsgOrSetCd(e, res))
+ .catch(err => common.handleException(e, err))
+ }
+
+ async _Authentication (e) {
+ if (e.isMaster) return true
+ const { allowPM, limit } = Config.setu
+ if (!allowPM && !e.isGroup) {
+ e.reply('主人已禁用私聊该功能')
+ return false
+ }
+ if (!common.checkSeSePermission(e, 'sesepro')) return false
+ if (!await common.limit(e.user_id, 'setu', limit)) {
+ e.reply('您已达今日「setu」次数上限', true, { at: true })
+ return false
+ }
+ return true
+ }
+
+ // 设置群撤回间隔和cd
+ async setGroupRecallAndCD (e) {
+ let num = e.msg.match(new RegExp(NumReg))
+ num = common.translateChinaNum(num[0])
+ let type = /撤回间隔/.test(e.msg)
+ setu.setGroupRecallTimeAndCd(e.group_id, num, type)
+ new Admin().SeSe_Settings(e)
+ }
+
+ // 开启r18
+ async setSeSe (e) {
+ let isopen = !!/开启/.test(e.msg)
+ setu.setR18(e.group_id, isopen)
+ new Admin().SeSe_Settings(e)
+ }
+
+ // 指令设置
+ async setCd (e) {
+ let reg = `^#?设置cd\\s?((\\d+)\\s)?(${NumReg})(s|秒)?$`
+ let regRet = e.msg.match(new RegExp(reg))
+ let qq = e.message.find(item => item.type == 'at')?.qq ?? regRet[2]
+ let cd = common.translateChinaNum(regRet[3])
+ if (!qq) return e.reply('❎ 请输入要设置QQ', true)
+ if (!cd) return e.reply('❎ CD为空,请检查', true)
+ setu.setUserCd(e, qq ?? regRet[2], cd)
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/state.js b/Yunzai/plugins/yenai-plugin/apps/state.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ca61520cfc1c6e8ad49b7c9391fec8f5ec6a66b
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/state.js
@@ -0,0 +1,175 @@
+import _ from 'lodash'
+import { createRequire } from 'module'
+import moment from 'moment'
+import os from 'os'
+import plugin from '../../../lib/plugins/plugin.js'
+import { Config, Version, Plugin_Name } from '../components/index.js'
+import { status } from '../constants/other.js'
+import { State, common, puppeteer } from '../model/index.js'
+const require = createRequire(import.meta.url)
+
+let interval = false
+export class NewState extends plugin {
+ constructor () {
+ super({
+ name: '椰奶状态',
+ event: 'message',
+ priority: 50,
+ rule: [
+ {
+ reg: '^#?(椰奶)?(状态|监控)(pro)?$',
+ fnc: 'state'
+ }
+ ]
+
+ })
+ }
+
+ async state (e) {
+ if (e.msg.includes('监控')) {
+ return await puppeteer.render('state/monitor', {
+ chartData: JSON.stringify(State.chartData)
+ }, {
+ e,
+ scale: 1.4
+ })
+ }
+
+ if (!/椰奶/.test(e.msg) && !Config.whole.state) return false
+
+ if (!State.si) return e.reply('❎ 没有检测到systeminformation依赖,请运行:"pnpm add systeminformation -w"进行安装')
+
+ // 防止多次触发
+ if (interval) { return false } else interval = true
+ // 系统
+ let FastFetch; let HardDisk
+ let otherInfo = []
+ // 其他信息
+ otherInfo.push({
+ first: '系统',
+ tail: State.osInfo?.distro
+ })
+ // 网络
+ otherInfo.push(State.getnetwork)
+ // 插件数量
+ otherInfo.push(State.getPluginNum)
+ let promiseTaskList = [
+ State.getFastFetch(e).then(res => { FastFetch = res }),
+ State.getFsSize().then(res => { HardDisk = res })
+ ]
+
+ // 网络测试
+ let psTest = []
+ let { psTestSites, psTestTimeout, backdrop } = Config.state
+ State.chartData.backdrop = backdrop
+ psTestSites && promiseTaskList.push(...psTestSites?.map(i => State.getNetworkLatency(i.url, psTestTimeout).then(res => psTest.push({
+ first: i.name,
+ tail: res
+ }))))
+ // 执行promise任务
+ await Promise.all(promiseTaskList)
+ // 可视化数据
+ let visualData = _.compact(await Promise.all([
+ // CPU板块
+ State.getCpuInfo(),
+ // 内存板块
+ State.getMemUsage(),
+ // GPU板块
+ State.getGPU(),
+ // Node板块
+ State.getNodeInfo()
+ ]))
+ const defaultAvatar = `../../../../../plugins/${Plugin_Name}/resources/state/img/default_avatar.jpg`
+ // 发
+ const sent = await redis.get('Yz:count:sendMsg:total') || 0
+ // 图片
+ const screenshot = await redis.get('Yz:count:screenshot:total') || 0
+ // 机器人名称
+ const BotName = Version.name
+ // 系统运行时间
+ const systime = common.formatTime(os.uptime(), 'dd天hh小时mm分', false)
+ // 日历
+ const calendar = moment().format('YYYY-MM-DD HH:mm:ss')
+ // nodejs版本
+ const nodeVersion = process.version
+ let BotStatus = ""
+
+ /** bot列表 */
+ let BotList = [e.self_id]
+ /** TRSS */
+ if (e.msg.includes("pro") && Array.isArray(Bot?.uin)) {
+ BotList = Bot.uin
+ }
+ /** ws、qg、wx等多bot */
+ else if (!Array.isArray(Bot?.uin) && Bot?.adapter && Bot.adapter.includes(Bot.uin)) {
+ BotList = Bot.adapter
+ }
+
+ for (const i of BotList) {
+ const bot = Bot[i]
+ if (!bot?.uin) continue
+ // 头像
+ const avatar = bot.avatar || (Number(bot.uin) ? `https://q1.qlogo.cn/g?b=qq&s=0&nk=${bot.uin}` : defaultAvatar)
+ // 昵称
+ const nickname = bot.nickname || "未知"
+ // 在线状态
+ const onlineStatus = status[bot.status] || "在线"
+ // 登录平台版本
+ const platform = bot.apk ? `${bot.apk.display} v${bot.apk.version}` : bot.version.version || "未知"
+ // 收
+ const recv = bot.stat?.recv_msg_cnt || "未知"
+ // 好友数
+ const friendQuantity = Array.from(bot.fl.values()).length
+ // 群数
+ const groupQuantity = Array.from(bot.gl.values()).length
+ // 运行时间
+ const runTime = common.formatTime(Date.now() / 1000 - bot.stat?.start_time, 'dd天hh小时mm分', false)
+ // Bot版本
+ const botVersion = bot.version ? `${bot.version.name}(${bot.version.id})${bot.apk ? ` ${bot.version.version}` : ""}` : `ICQQ(QQ) v${require('icqq/package.json').version}`
+ BotStatus += `
+
+
+

+
+
+
+
+`
+ }
+ // 渲染数据
+ let data = {
+ BotStatus,
+ chartData: JSON.stringify(common.checkIfEmpty(State.chartData, ['echarts_theme', 'cpu', 'ram']) ? undefined : State.chartData),
+ // 硬盘内存
+ HardDisk,
+ // FastFetch
+ FastFetch,
+ // 硬盘速率
+ fsStats: State.DiskSpeed,
+ // 可视化数据
+ visualData,
+ // 其他数据
+ otherInfo: _.compact(otherInfo),
+ psTest: _.isEmpty(psTest) ? false : psTest
+ }
+
+ // 渲染图片
+ await puppeteer.render('state/state', {
+ ...data
+ }, {
+ e,
+ scale: 1.4
+ })
+
+ interval = false
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/update.js b/Yunzai/plugins/yenai-plugin/apps/update.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea8d004f2fca457312b4045d8c994785332cc66b
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/update.js
@@ -0,0 +1,255 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import { createRequire } from 'module'
+import _ from 'lodash'
+import { Restart } from '../../other/restart.js'
+import common from '../lib/common/common.js'
+
+const require = createRequire(import.meta.url)
+const { exec, execSync } = require('child_process')
+
+// 是否在更新中
+let uping = false
+
+/**
+ * 处理插件更新
+ */
+export class Update extends plugin {
+ constructor () {
+ super({
+ name: '椰奶更新插件',
+ event: 'message',
+ priority: 1000,
+ rule: [
+ {
+ reg: '^#*椰奶(插件)?(强制)?更新$',
+ fnc: 'update'
+ }
+ ]
+ })
+ }
+
+ /**
+ * rule - 更新椰奶插件
+ * @returns
+ */
+ async update () {
+ if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
+
+ /** 检查是否正在更新中 */
+ if (uping) {
+ await this.reply('已有命令更新中..请勿重复操作')
+ return
+ }
+
+ /** 检查git安装 */
+ if (!(await this.checkGit())) return
+
+ const isForce = this.e.msg.includes('强制')
+
+ /** 执行更新 */
+ await this.runUpdate(isForce)
+
+ /** 是否需要重启 */
+ if (this.isUp) {
+ // await this.reply("更新完毕,请重启云崽后生效")
+ setTimeout(() => this.restart(), 2000)
+ }
+ }
+
+ restart () {
+ new Restart(this.e).restart()
+ }
+
+ /**
+ * 椰奶插件更新函数
+ * @param {boolean} isForce 是否为强制更新
+ * @returns
+ */
+ async runUpdate (isForce) {
+ const _path = './plugins/yenai-plugin/'
+ let command = `git -C ${_path} pull --no-rebase`
+ if (isForce) {
+ command = `git -C ${_path} reset --hard origin && ${command}`
+ this.e.reply('正在执行强制更新操作,请稍等')
+ } else {
+ this.e.reply('正在执行更新操作,请稍等')
+ }
+ /** 获取上次提交的commitId,用于获取日志时判断新增的更新日志 */
+ this.oldCommitId = await this.getcommitId('yenai-plugin')
+ uping = true
+ let ret = await this.execSync(command)
+ uping = false
+
+ if (ret.error) {
+ logger.mark(`${this.e.logFnc} 更新失败:椰奶插件`)
+ this.gitErr(ret.error, ret.stdout)
+ return false
+ }
+
+ /** 获取插件提交的最新时间 */
+ let time = await this.getTime('yenai-plugin')
+
+ if (/(Already up[ -]to[ -]date|已经是最新的)/.test(ret.stdout)) {
+ await this.reply(`椰奶插件已经是最新版本\n最后更新时间:${time}`)
+ } else {
+ await this.reply(`椰奶插件\n最后更新时间:${time}`)
+ this.isUp = true
+ /** 获取椰奶组件的更新日志 */
+ let log = await this.getLog('yenai-plugin')
+ await this.reply(log)
+ }
+
+ logger.mark(`${this.e.logFnc} 最后更新时间:${time}`)
+
+ return true
+ }
+
+ /**
+ * 获取椰奶插件的更新日志
+ * @param {string} plugin 插件名称
+ * @returns
+ */
+ async getLog (plugin = '') {
+ let cm = `cd ./plugins/${plugin}/ && git log -20 --oneline --pretty=format:"%h||[%cd] %s" --date=format:"%m-%d %H:%M"`
+
+ let logAll
+ try {
+ logAll = await execSync(cm, { encoding: 'utf-8' })
+ } catch (error) {
+ logger.error(error.toString())
+ this.reply(error.toString())
+ }
+
+ if (!logAll) return false
+
+ logAll = logAll.split('\n')
+
+ let log = []
+ for (let str of logAll) {
+ str = str.split('||')
+ if (str[0] == this.oldCommitId) break
+ if (str[1].includes('Merge branch')) continue
+ log.push(str[1])
+ }
+ let line = log.length
+ log = log.join('\n\n')
+
+ if (log.length <= 0) return ''
+
+ let end = ''
+ end =
+ '更多详细信息,请前往gitee查看\nhttps://gitee.com/yeyang52/yenai-plugin/blob/master/CHANGELOG.md'
+ let forwardMsg = [
+ `椰奶插件更新日志,共${line}条`, log, end
+ ]
+ log = await common.getforwardMsg(this.e, forwardMsg, {
+ shouldSendMsg: false
+ })
+
+ return log
+ }
+
+ /**
+ * 获取上次提交的commitId
+ * @param {string} plugin 插件名称
+ * @returns
+ */
+ async getcommitId (plugin = '') {
+ let cm = `git -C ./plugins/${plugin}/ rev-parse --short HEAD`
+
+ let commitId = await execSync(cm, { encoding: 'utf-8' })
+ commitId = _.trim(commitId)
+
+ return commitId
+ }
+
+ /**
+ * 获取本次更新插件的最后一次提交时间
+ * @param {string} plugin 插件名称
+ * @returns
+ */
+ async getTime (plugin = '') {
+ let cm = `cd ./plugins/${plugin}/ && git log -1 --oneline --pretty=format:"%cd" --date=format:"%m-%d %H:%M"`
+
+ let time = ''
+ try {
+ time = await execSync(cm, { encoding: 'utf-8' })
+ time = _.trim(time)
+ } catch (error) {
+ logger.error(error.toString())
+ time = '获取时间失败'
+ }
+ return time
+ }
+
+ /**
+ * 处理更新失败的相关函数
+ * @param {string} err
+ * @param {string} stdout
+ * @returns
+ */
+ async gitErr (err, stdout) {
+ let msg = '更新失败!'
+ let errMsg = err.toString()
+ stdout = stdout.toString()
+
+ if (errMsg.includes('Timed out')) {
+ let remote = errMsg.match(/'(.+?)'/g)[0].replace(/'/g, '')
+ await this.reply(msg + `\n连接超时:${remote}`)
+ return
+ }
+
+ if (/Failed to connect|unable to access/g.test(errMsg)) {
+ let remote = errMsg.match(/'(.+?)'/g)[0].replace(/'/g, '')
+ await this.reply(msg + `\n连接失败:${remote}`)
+ return
+ }
+
+ if (errMsg.includes('be overwritten by merge')) {
+ await this.reply(
+ msg +
+ `存在冲突:\n${errMsg}\n` +
+ '请解决冲突后再更新,或者执行#强制更新,放弃本地修改'
+ )
+ return
+ }
+
+ if (stdout.includes('CONFLICT')) {
+ await this.reply([
+ msg + '存在冲突\n',
+ errMsg,
+ stdout,
+ '\n请解决冲突后再更新,或者执行#强制更新,放弃本地修改'
+ ])
+ return
+ }
+
+ await this.reply([errMsg, stdout])
+ }
+
+ /**
+ * 异步执行git相关命令
+ * @param {string} cmd git命令
+ * @returns
+ */
+ async execSync (cmd) {
+ return new Promise((resolve, reject) => {
+ exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ /**
+ * 检查git是否安装
+ * @returns
+ */
+ async checkGit () {
+ let ret = await execSync('git --version', { encoding: 'utf-8' })
+ if (!ret || !ret.includes('git version')) {
+ await this.reply('请先安装git')
+ return false
+ }
+ return true
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/apps/version.js b/Yunzai/plugins/yenai-plugin/apps/version.js
new file mode 100644
index 0000000000000000000000000000000000000000..537ab16c50f946c19af29b0c8b6d0449a6558472
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/apps/version.js
@@ -0,0 +1,52 @@
+import plugin from '../../../lib/plugins/plugin.js'
+import { update } from '../../other/update.js'
+import { Version, Plugin_Name } from '../components/index.js'
+import { puppeteer } from '../model/index.js'
+export class NewVersion extends plugin {
+ constructor () {
+ super({
+ name: '椰奶版本信息',
+ event: 'message',
+ priority: 400,
+ rule: [
+ {
+ reg: '^#?椰奶(插件)?版本$',
+ fnc: 'plugin_version'
+ },
+ {
+ reg: '^#?椰奶(插件)?更新日志$',
+ fnc: 'update_log'
+ }
+ ]
+ })
+ this.key = 'yenai:restart'
+ }
+
+ async plugin_version () {
+ return versionInfo(this.e)
+ }
+
+ async update_log () {
+ // eslint-disable-next-line new-cap
+ let Update_Plugin = new update()
+ Update_Plugin.e = this.e
+ Update_Plugin.reply = this.reply
+
+ if (Update_Plugin.getPlugin(Plugin_Name)) {
+ this.e.reply(await Update_Plugin.getLog(Plugin_Name))
+ }
+ return true
+ }
+}
+
+async function versionInfo (e) {
+ return await puppeteer.render(
+ 'help/version-info',
+ {
+ currentVersion: Version.ver,
+ changelogs: Version.logs,
+ elem: 'cryo'
+ },
+ { e, scale: 1.4 }
+ )
+}
diff --git a/Yunzai/plugins/yenai-plugin/components/Config.js b/Yunzai/plugins/yenai-plugin/components/Config.js
new file mode 100644
index 0000000000000000000000000000000000000000..c44b0b27093cf88f4573fe728e85f36e13b835d0
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/components/Config.js
@@ -0,0 +1,231 @@
+
+import YAML from 'yaml'
+import chokidar from 'chokidar'
+import fs from 'node:fs'
+import YamlReader from './YamlReader.js'
+import cfg from '../../../lib/config/config.js'
+import loader from '../../../lib/plugins/loader.js'
+import _ from 'lodash'
+import moment from 'moment'
+
+const Path = process.cwd()
+const Plugin_Name = 'yenai-plugin'
+const Plugin_Path = `${Path}/plugins/${Plugin_Name}`
+class Config {
+ constructor () {
+ this.config = {}
+
+ /** 监听文件 */
+ this.watcher = { config: {}, defSet: {} }
+
+ this.initCfg()
+ }
+
+ /** 初始化配置 */
+ initCfg () {
+ let path = `${Plugin_Path}/config/config/`
+ let pathDef = `${Plugin_Path}/config/default_config/`
+ const files = fs.readdirSync(pathDef).filter(file => file.endsWith('.yaml'))
+ for (let file of files) {
+ if (!fs.existsSync(`${path}${file}`)) {
+ fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
+ }
+ this.watch(`${path}${file}`, file.replace('.yaml', ''), 'config')
+ }
+ }
+
+ /** 群配置 */
+ getGroup (groupId = '') {
+ let config = this.getConfig('whole')
+ let group = this.getConfig('group')
+ let defCfg = this.getdefSet('whole')
+
+ if (group[groupId]) {
+ return { ...defCfg, ...config, ...group[groupId] }
+ }
+ return { ...defCfg, ...config }
+ }
+
+ /** 主人QQ */
+ get masterQQ () {
+ return cfg.masterQQ
+ }
+
+ /** 获取全局设置 */
+ get whole () {
+ return this.getDefOrConfig('whole')
+ }
+
+ /** 进群验证配置 */
+ get groupverify () {
+ return this.getDefOrConfig('groupverify')
+ }
+
+ /** 头衔屏蔽词 */
+ get groupTitle () {
+ return this.getDefOrConfig('groupTitle')
+ }
+
+ /** 加群通知 */
+ get groupAdd () {
+ return this.getDefOrConfig('groupAdd')
+ }
+
+ /** 代理 */
+ get proxy () {
+ return this.getDefOrConfig('proxy')
+ }
+
+ /** pixiv */
+ get pixiv () {
+ return this.getDefOrConfig('pixiv')
+ }
+
+ /** 哔咔 */
+ get bika () {
+ return this.getDefOrConfig('bika')
+ }
+
+ /** 搜图 */
+ get picSearch () {
+ return this.getDefOrConfig('picSearch')
+ }
+
+ /** setu */
+ get setu () {
+ return this.getDefOrConfig('setu')
+ }
+
+ /** 状态 */
+ get state () {
+ return this.getDefOrConfig('state')
+ }
+
+ /** 默认配置和用户配置 */
+ getDefOrConfig (name) {
+ let def = this.getdefSet(name)
+ let config = this.getConfig(name)
+ return { ...def, ...config }
+ }
+
+ /** 默认配置 */
+ getdefSet (name) {
+ return this.getYaml('default_config', name)
+ }
+
+ /** 用户配置 */
+ getConfig (name) {
+ return this.getYaml('config', name)
+ }
+
+ /**
+ * 获取配置yaml
+ * @param type 默认跑配置-defSet,用户配置-config
+ * @param name 名称
+ */
+ getYaml (type, name) {
+ let file = `${Plugin_Path}/config/${type}/${name}.yaml`
+ let key = `${type}.${name}`
+
+ if (this.config[key]) return this.config[key]
+
+ this.config[key] = YAML.parse(
+ fs.readFileSync(file, 'utf8')
+ )
+
+ this.watch(file, name, type)
+
+ return this.config[key]
+ }
+
+ /** 监听配置文件 */
+ watch (file, name, type = 'default_config') {
+ let key = `${type}.${name}`
+
+ if (this.watcher[key]) return
+
+ const watcher = chokidar.watch(file)
+ watcher.on('change', path => {
+ delete this.config[key]
+ if (typeof Bot == 'undefined') return
+ logger.mark(`[Yenai-Plugin][修改配置文件][${type}][${name}]`)
+ if (this[`change_${name}`]) {
+ this[`change_${name}`]()
+ }
+ })
+
+ this.watcher[key] = watcher
+ }
+
+ /**
+ * @description: 修改设置
+ * @param {String} name 文件名
+ * @param {String} key 修改的key值
+ * @param {String|Number} value 修改的value值
+ * @param {'config'|'default_config'} type 配置文件或默认
+ */
+ modify (name, key, value, type = 'config') {
+ let path = `${Plugin_Path}/config/${type}/${name}.yaml`
+ new YamlReader(path).set(key, value)
+ delete this.config[`${type}.${name}`]
+ }
+
+ /**
+ * @description: 群单独设置
+ * @param {String|Number} groupId 群号
+ * @param {String} key 设置项
+ * @param {unknown} value
+ */
+ aloneModify (groupId, key, value, isDel) {
+ let path = `${Plugin_Path}/config/config/group.yaml`
+ let yaml = new YamlReader(path)
+ let groupCfg = yaml.jsonData[groupId] ?? {}
+ isDel ? delete groupCfg[key] : groupCfg[key] = value
+ yaml.set(groupId, groupCfg)
+ delete this.config['config.group']
+ }
+
+ /**
+ * @description: 修改配置数组
+ * @param {String} name 文件名
+ * @param {String|Number} key key值
+ * @param {String|Number} value value
+ * @param {'add'|'del'} category 类别 add or del
+ * @param {'config'|'default_config'} type 配置文件或默认
+ */
+ modifyarr (name, key, value, category = 'add', type = 'config') {
+ let path = `${Plugin_Path}/config/${type}/${name}.yaml`
+ let yaml = new YamlReader(path)
+ if (category == 'add') {
+ yaml.addIn(key, value)
+ } else {
+ let index = yaml.jsonData[key].indexOf(value)
+ yaml.delete(`${key}.${index}`)
+ }
+ }
+
+ async change_picApi () {
+ let tmp = {}
+
+ logger.debug('[Yenai-Plugin]api接口修改,重载fun.js')
+ tmp = await import(`../apps/fun.js?${moment().format('x')}`)
+
+ _.forEach(tmp, (p) => {
+ /* eslint-disable new-cap */
+ let plugin = new p()
+ for (let i in loader.priority) {
+ if (loader.priority[i].key == Plugin_Name && loader.priority[i].name == '椰奶娱乐') {
+ loader.priority[i].class = p
+ loader.priority[i].priority = plugin.priority
+ }
+ }
+ })
+ }
+
+ async change_pixiv () {
+ let pixiv = (await import('../model/index.js')).Pixiv
+ let PixivApi = (await import('../model/Pixiv/api.js')).default
+ pixiv.PixivClient = new PixivApi(this.pixiv.refresh_token)
+ }
+}
+export default new Config()
diff --git a/Yunzai/plugins/yenai-plugin/components/Data.js b/Yunzai/plugins/yenai-plugin/components/Data.js
new file mode 100644
index 0000000000000000000000000000000000000000..be0c44f5e8e13b9e262083a2345d6610bf0adced
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/components/Data.js
@@ -0,0 +1,246 @@
+import _ from 'lodash'
+import fs from 'fs'
+import path from 'path'
+
+const _path = process.cwd()
+const plugin = 'yenai-plugin'
+const getRoot = (root = '') => {
+ if (root === 'root' || root === 'yunzai') {
+ root = `${_path}/`
+ } else if (!root) {
+ root = `${_path}/plugins/${plugin}/`
+ }
+ return root
+}
+
+let Data = {
+
+ /*
+ * 根据指定的path依次检查与创建目录
+ * */
+ createDir (path = '', root = '', includeFile = false) {
+ root = getRoot(root)
+ let pathList = path.split('/')
+ let nowPath = root
+ pathList.forEach((name, idx) => {
+ name = name.trim()
+ if (!includeFile && idx <= pathList.length - 1) {
+ nowPath += name + '/'
+ if (name) {
+ if (!fs.existsSync(nowPath)) {
+ fs.mkdirSync(nowPath)
+ }
+ }
+ }
+ })
+ },
+
+ /** 读取json */
+ readJSON (file = '', root = '') {
+ root = getRoot(root)
+ if (fs.existsSync(`${root}/${file}`)) {
+ try {
+ return JSON.parse(fs.readFileSync(`${root}/${file}`, 'utf8'))
+ } catch (e) {
+ console.log(e)
+ }
+ }
+ return {}
+ },
+
+ /** 写JSON */
+ writeJSON (file, data, root = '', space = '\t') {
+ // 检查并创建目录
+ Data.createDir(file, root, true)
+ root = getRoot(root)
+ // delete data._res
+ try {
+ fs.writeFileSync(`${root}/${file}`, JSON.stringify(data, null, space))
+ return true
+ } catch (err) {
+ logger.error(err)
+ return false
+ }
+ },
+
+ async getCacheJSON (key) {
+ try {
+ let txt = await redis.get(key)
+ if (txt) {
+ return JSON.parse(txt)
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ return {}
+ },
+
+ async setCacheJSON (key, data, EX = 3600 * 24 * 90) {
+ await redis.set(key, JSON.stringify(data), { EX })
+ },
+
+ async importModule (file, root = '') {
+ root = getRoot(root)
+ if (!/\.js$/.test(file)) {
+ file = file + '.js'
+ }
+ if (fs.existsSync(`${root}/${file}`)) {
+ try {
+ let data = await import(`file://${root}/${file}?t=${new Date() * 1}`)
+ return data || {}
+ } catch (e) {
+ console.log(e)
+ }
+ }
+ return {}
+ },
+
+ async importDefault (file, root) {
+ let ret = await Data.importModule(file, root)
+ return ret.default || {}
+ },
+
+ async import (name) {
+ return await Data.importModule(`components/optional-lib/${name}.js`)
+ },
+
+ async importCfg (key) {
+ let sysCfg = await Data.importModule(`config/system/${key}_system.js`)
+ let diyCfg = await Data.importModule(`config/${key}.js`)
+ if (diyCfg.isSys) {
+ console.error(`yenai-plugin: config/${key}.js无效,已忽略`)
+ console.error(`如需配置请复制config/${key}_default.js为config/${key}.js,请勿复制config/system下的系统文件`)
+ diyCfg = {}
+ }
+ return {
+ sysCfg,
+ diyCfg
+ }
+ },
+
+ /*
+ * 返回一个从 target 中选中的属性的对象
+ *
+ * keyList : 获取字段列表,逗号分割字符串
+ * key1, key2, toKey1:fromKey1, toKey2:fromObj.key
+ *
+ * defaultData: 当某个字段为空时会选取defaultData的对应内容
+ * toKeyPrefix:返回数据的字段前缀,默认为空。defaultData中的键值无需包含toKeyPrefix
+ *
+ * */
+
+ getData (target, keyList = '', cfg = {}) {
+ target = target || {}
+ let defaultData = cfg.defaultData || {}
+ let ret = {}
+ // 分割逗号
+ if (typeof (keyList) === 'string') {
+ keyList = keyList.split(',')
+ }
+
+ _.forEach(keyList, (keyCfg) => {
+ // 处理通过:指定 toKey & fromKey
+ let _keyCfg = keyCfg.split(':')
+ let keyTo = _keyCfg[0].trim()
+ let keyFrom = (_keyCfg[1] || _keyCfg[0]).trim()
+ let keyRet = keyTo
+ if (cfg.lowerFirstKey) {
+ keyRet = _.lowerFirst(keyRet)
+ }
+ if (cfg.keyPrefix) {
+ keyRet = cfg.keyPrefix + keyRet
+ }
+ // 通过Data.getVal获取数据
+ ret[keyRet] = Data.getVal(target, keyFrom, defaultData[keyTo], cfg)
+ })
+ return ret
+ },
+
+ getVal (target, keyFrom, defaultValue) {
+ return _.get(target, keyFrom, defaultValue)
+ },
+
+ // 异步池,聚合请求
+ async asyncPool (poolLimit, array, iteratorFn) {
+ const ret = [] // 存储所有的异步任务
+ const executing = [] // 存储正在执行的异步任务
+ for (const item of array) {
+ // 调用iteratorFn函数创建异步任务
+ const p = Promise.resolve().then(() => iteratorFn(item, array))
+ // 保存新的异步任务
+ ret.push(p)
+
+ // 当poolLimit值小于或等于总任务个数时,进行并发控制
+ if (poolLimit <= array.length) {
+ // 当任务完成后,从正在执行的任务数组中移除已完成的任务
+ const e = p.then(() => executing.splice(executing.indexOf(e), 1))
+ executing.push(e) // 保存正在执行的异步任务
+ if (executing.length >= poolLimit) {
+ // 等待较快的任务执行完成
+ await Promise.race(executing)
+ }
+ }
+ }
+ return Promise.all(ret)
+ },
+
+ // sleep
+ sleep (ms) {
+ return new Promise((resolve) => setTimeout(resolve, ms))
+ },
+
+ // 获取默认值
+ def () {
+ for (let idx in arguments) {
+ if (!_.isUndefined(arguments[idx])) {
+ return arguments[idx]
+ }
+ }
+ },
+
+ // 循环字符串回调
+ eachStr: (arr, fn) => {
+ if (_.isString(arr)) {
+ arr = arr.replace(/\s*(;|;|、|,)\s*/, ',')
+ arr = arr.split(',')
+ } else if (_.isNumber(arr)) {
+ arr = [arr.toString()]
+ }
+ _.forEach(arr, (str, idx) => {
+ if (!_.isUndefined(str)) {
+ fn(str.trim ? str.trim() : str, idx)
+ }
+ })
+ },
+
+ regRet (reg, txt, idx) {
+ if (reg && txt) {
+ let ret = reg.exec(txt)
+ if (ret && ret[idx]) {
+ return ret[idx]
+ }
+ }
+ return false
+ },
+ /** 读取文件夹和子文件夹指定后缀文件名 */
+ readDirRecursive (directory, extension, excludeDir) {
+ let files = fs.readdirSync(directory)
+
+ let jsFiles = files.filter(file => path.extname(file) === `.${extension}`)
+
+ files.filter(file => fs.statSync(path.join(directory, file)).isDirectory())
+ .forEach(subdirectory => {
+ if (subdirectory === excludeDir) {
+ return
+ }
+
+ const subdirectoryPath = path.join(directory, subdirectory)
+ jsFiles.push(...Data.readDirRecursive(subdirectoryPath, extension, excludeDir)
+ .map(fileName => path.join(subdirectory, fileName)))
+ })
+
+ return jsFiles
+ }
+}
+
+export default Data
diff --git a/Yunzai/plugins/yenai-plugin/components/Version.js b/Yunzai/plugins/yenai-plugin/components/Version.js
new file mode 100644
index 0000000000000000000000000000000000000000..97d70f7e706caa2406a13d57bef17903564e51c2
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/components/Version.js
@@ -0,0 +1,113 @@
+import fs from 'fs'
+import _ from 'lodash'
+import cfg from '../../../lib/config/config.js'
+const Plugin_Path = `${process.cwd()}/plugins/yenai-plugin`
+const README_path = `${Plugin_Path}/README.md`
+const CHANGELOG_path = `${Plugin_Path}/CHANGELOG.md`
+const yunzai_ver = `v${cfg.package.version}`
+
+let logs = {}
+let changelogs = []
+let currentVersion
+let versionCount = 2
+
+const getLine = function (line) {
+ line = line.replace(/(^\s*\*|\r)/g, '')
+ line = line.replace(/\s*`([^`]+`)/g, '$1')
+ line = line.replace(/`\s*/g, '')
+ line = line.replace(/\s*\*\*([^*]+\*\*)/g, '$1')
+ line = line.replace(/\*\*\s*/g, '')
+ line = line.replace(/ⁿᵉʷ/g, '')
+ return line
+}
+
+try {
+ if (fs.existsSync(CHANGELOG_path)) {
+ logs = fs.readFileSync(CHANGELOG_path, 'utf8') || ''
+ logs = logs.replace(/\t/g, ' ').split('\n')
+ let temp = {}
+ let lastLine = {}
+ _.forEach(logs, (line) => {
+ if (versionCount <= -1) {
+ return false
+ }
+ let versionRet = /^#\s*([0-9a-zA-Z\\.~\s]+?)\s*$/.exec(line.trim())
+ if (versionRet && versionRet[1]) {
+ let v = versionRet[1].trim()
+ if (!currentVersion) {
+ currentVersion = v
+ } else {
+ changelogs.push(temp)
+ if (/0\s*$/.test(v) && versionCount > 0) {
+ // versionCount = 0
+ versionCount--
+ } else {
+ versionCount--
+ }
+ }
+ temp = {
+ version: v,
+ logs: []
+ }
+ } else {
+ if (!line.trim()) {
+ return
+ }
+ if (/^\*/.test(line)) {
+ lastLine = {
+ title: getLine(line),
+ logs: []
+ }
+ if (!temp.logs) {
+ temp = {
+ version: line,
+ logs: []
+ }
+ }
+ temp.logs.push(lastLine)
+ } else if (/^\s{2,}\*/.test(line)) {
+ lastLine.logs.push(getLine(line))
+ }
+ }
+ })
+ }
+} catch (e) {
+ logger.error(e)
+ // do nth
+}
+
+try {
+ if (fs.existsSync(README_path)) {
+ let README = fs.readFileSync(README_path, 'utf8') || ''
+ let reg = /版本:(.*)/.exec(README)
+ if (reg) {
+ currentVersion = reg[1]
+ }
+ }
+} catch (err) { }
+
+let yunzaiName = cfg.package.name
+if (yunzaiName == 'miao-yunzai') {
+ yunzaiName = 'Miao-Yunzai'
+} else if (yunzaiName == 'yunzai') {
+ yunzaiName = 'Yunzai-Bot'
+} else if (yunzaiName == 'trss-yunzai') {
+ yunzaiName = 'TRSS-Yunzai'
+} else {
+ yunzaiName = _.capitalize(yunzaiName)
+}
+let Version = {
+ get ver () {
+ return currentVersion
+ },
+ get name () {
+ return yunzaiName
+ },
+ get yunzai () {
+ return yunzai_ver
+ },
+ get logs () {
+ return changelogs
+ }
+}
+export default Version
diff --git a/Yunzai/plugins/yenai-plugin/components/YamlReader.js b/Yunzai/plugins/yenai-plugin/components/YamlReader.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5b757801f456b81ec80dff7ea2a1bdee38fa517
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/components/YamlReader.js
@@ -0,0 +1,83 @@
+import fs from 'fs'
+import YAML from 'yaml'
+import _ from 'lodash'
+import chokidar from 'chokidar'
+// import Constant from '../server/constant/Constant.js'
+
+export default class YamlReader {
+ /**
+ * 读写yaml文件
+ *
+ * @param yamlPath yaml文件绝对路径
+ * @param isWatch 是否监听文件变化
+ */
+ constructor (yamlPath, isWatch = false) {
+ this.yamlPath = yamlPath
+ this.isWatch = isWatch
+ this.initYaml()
+ }
+
+ initYaml () {
+ // parseDocument 将会保留注释
+ this.document = YAML.parseDocument(fs.readFileSync(this.yamlPath, 'utf8'))
+ if (this.isWatch && !this.watcher) {
+ this.watcher = chokidar.watch(this.yamlPath).on('change', () => {
+ if (this.isSave) {
+ this.isSave = false
+ return
+ }
+ this.initYaml()
+ })
+ }
+ }
+
+ /** 返回读取的对象 */
+ get jsonData () {
+ if (!this.document) {
+ return null
+ }
+ return this.document.toJSON()
+ }
+
+ /* 检查集合是否包含key的值 */
+ has (keyPath) {
+ return this.document.hasIn(keyPath.split('.'))
+ }
+
+ /* 返回key的值 */
+ get (keyPath) {
+ return _.get(this.jsonData, keyPath)
+ }
+
+ /* 修改某个key的值 */
+ set (keyPath, value) {
+ this.document.setIn([keyPath], value)
+ this.save()
+ }
+
+ /* 删除key */
+ delete (keyPath) {
+ this.document.deleteIn(keyPath.split('.'))
+ this.save()
+ }
+
+ // 数组添加数据
+ addIn (keyPath, value) {
+ this.document.addIn(keyPath.split('.'), value)
+ this.save()
+ }
+
+ // 彻底删除某个key
+ deleteKey (keyPath) {
+ let keys = keyPath.split('.')
+ keys = this.mapParentKeys(keys)
+ this.document.deleteIn(keys)
+ this.save()
+ }
+
+ save () {
+ this.isSave = true
+ let yaml = this.document.toString()
+ fs.writeFileSync(this.yamlPath, yaml, 'utf8')
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/components/index.js b/Yunzai/plugins/yenai-plugin/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ce2eae8d66eb347c826a4e537f65a47426275d14
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/components/index.js
@@ -0,0 +1,8 @@
+import Version from './Version.js'
+import Data from './Data.js'
+import Config from './Config.js'
+import YamlReader from './YamlReader.js'
+const Path = process.cwd()
+const Plugin_Name = 'yenai-plugin'
+const Plugin_Path = `${Path}/plugins/${Plugin_Name}`
+export { Config, Data, Version, Path, Plugin_Name, Plugin_Path, YamlReader }
diff --git a/Yunzai/plugins/yenai-plugin/config/config/.gitignore b/Yunzai/plugins/yenai-plugin/config/config/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c96a04f008ee21e260b28f7701595ed59e2839e3
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/config/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/bika.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/bika.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8e5da9ed211f1d41ff151127ea2e5c517c98bf6a
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/bika.yaml
@@ -0,0 +1,10 @@
+#是否允许私聊使用
+allowPM: true
+#每名用户每日使用次数限制 0则无限制
+limit: 30
+#哔咔图片直连,直接使用哔咔原图发送不使用图片反代,国内则需使用代理
+bikaDirectConnection: false
+#哔咔图片反代
+bikaImageProxy: p.sesepic.top/static
+#哔咔图片质量,可选值 ['low', 'medium', 'high', 'original'] 质量依次从低到高
+imageQuality: medium
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/group.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/group.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4c394cb925793364dbddac4b5d9924f2f114ced6
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/group.yaml
@@ -0,0 +1,16 @@
+#群单独设置 会覆盖掉全局设置 全局设置可用#椰奶设置查看 或 在whole.yaml查看
+123456:
+ groupMessage: false #群消息
+ grouptemporaryMessage: false #群临时消息
+ groupRecall: false #群撤回
+ groupInviteRequest: false #群邀请
+ groupAdminChange: false #群管理变动
+ groupNumberChange: false #群聊列表变动
+ groupMemberNumberChange: false #群成员变动
+ botBeenBanned: false #禁言
+ flashPhoto: false #闪照
+
+#请严格按照yaml格式设置 不需要的设置项可删除
+456789:
+ groupMessage: false #群消息
+ grouptemporaryMessage: false #群临时消息
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/groupAdd.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/groupAdd.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..65612aebd7581570c0e79b61f725f8551d8ae02e
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/groupAdd.yaml
@@ -0,0 +1,2 @@
+openGroup: []
+msg: 有一个加群通知,管理员快去看看吧~
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/groupverify.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/groupverify.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a6d453a25580ddd6ecd0dfb4d2592c8fb8112f07
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/groupverify.yaml
@@ -0,0 +1,21 @@
+#开启的群聊
+openGroup: []
+# 如需要分群,请按照下列格式添加 <以群号为字段> 的成功提示即可,0 字段代表默认回复
+SuccessMsgs:
+ 254974507: ✅ 验证成功,欢迎入群,群里有非常多的大佬给你透哦~~
+ 0: ✅ 验证成功,欢迎入群
+
+# 答案验证模式,可选:精确、模糊
+mode: 精确
+# 最多允许尝试次数
+times: 7
+# 是否开启最后一分钟提醒(仅在超时时长大于等于 120 秒时有效,true 开启,false 关闭)
+remindAtLastMinute: true
+# 超时时长(秒),建议至少一分钟(60 秒)
+time: 300
+# 随机算式的数字的随机范围
+range:
+ min: 10
+ max: 100
+#收到进群事件后延迟多少秒再发送验证信息(秒)
+DelayTime: 2
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/picApi.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/picApi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4796b49ca2cb64cdf3d12c17a9592e8d2b643386
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/picApi.yaml
@@ -0,0 +1,37 @@
+#注:修改后重启生效,请严格按照yaml语法进行修改,否则会出现意料之外的错误
+
+mode: true #指令匹配模式 true为精确匹配,false为模糊匹配
+#key值设置为要触发的词
+bs:
+ url: http://api.caonm.net/api/bhs/b.php #在url字段后面写接口链接
+
+ type: image
+ #根据接口指定类型类型包括 image text json 如不写则默认为image
+ # image指接口直接返回图片
+ # text指接口返回链接
+ # json指接口返回json字符串 ,返回json需指定path请参考以下json示例
+
+#也可以以"|"分隔设置多个触发词
+hs|黑丝|heisi:
+ url:
+ - http://api.caonm.net/api/bhs/h.php
+ - http://api.starrobotwl.com/api/heisi.php #可以采用这种格式进行一个关键词设置多个链接
+ #或者["http...", "http..."]这种格式,可百度"yaml配置数组写法"参考
+
+#返回json示例
+ecy:
+ url: https://sex.nyan.xyz/api/v2/
+ type: json
+ path: data[0].url #接口返回链接在 "data数组" 里面用 "[0]" 来指定数组的第几个值后再 ".url" 即可,最后必须指向图片链接
+
+#返回text示例
+meizi:
+ url: https://xiaobapi.top/api/xb/api/meizi.php
+ type: text
+
+bm:
+ url: http://iw233.cn/api.php?sort=yin #在url字段后面写链接,仅限直接返回图片的api
+
+sy: https://iw233.cn/api.php?sort=cat #或者直接写链接效果同上,仅限直接返回图片的api
+
+ay: https://api.r10086.com/img-api.php?zsy=原神
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/picSearch.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/picSearch.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a8300d6269304865c118c40e4ef456c9b617e171
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/picSearch.yaml
@@ -0,0 +1,29 @@
+#是否只有主人能用
+isMasterUse: false
+#是否允许私聊使用
+allowPM: true
+#每名用户每日搜索次数限制
+limit: 30
+#SauceNAO搜图apikey 请在 https://saucenao.com/user.php?page=search-api 进行获取
+SauceNAOApiKey:
+#SauceNAO搜图相似度低于这个百分比将被认定为相似度过低
+SauceNAOMinSim: 60
+#saucanao 得到 NSFW 结果时隐藏缩略图,可选 0~3,严格程度依次增加
+#0-不隐藏,1-隐藏明确为 NSFW 的缩略图,2-隐藏明确和可能为 NSFW 的缩略图,3-只显示明确为非 NSFW 的缩略图
+hideImgWhenSaucenaoNSFW: 0
+#绕过 Cloudflare Challenge 所使用的 TLS 版本,建议可选值:["TLSv1.1", "TLSv1.2"]
+cfTLSVersion: TLSv1.1
+#是否使用 Puppeteer 请求 ascii2d 以绕过 cf js challenge 注:该功能需安装puppeteer-extra 和 puppeteer-extra-plugin-stealth 依赖
+ascii2dUsePuppeteer: false
+#ascii2d搜图返回结果的最大数量
+ascii2dResultMaxQuantity: 3
+#隐藏所有搜索结果的缩略图
+hideImg: false
+#whatanime 得到 R18 结果时隐藏结果缩略图
+hideImgWhenWhatanimeR18: false
+#whatanime 发送预览视频,R18 结果不会发送
+whatanimeSendVideo: false
+# 是否在 saucenao 相似度过低时自动使用 ascii2d
+useAscii2dWhenLowAcc: true
+# 是否在 saucenao 搜索失败时自动使用 ascii2d
+useAscii2dWhenFailed: true
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/pixiv.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/pixiv.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..14979eec6bfbfbefdc37b6306d39efd69e1debae
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/pixiv.yaml
@@ -0,0 +1,14 @@
+#是否允许私聊使用
+allowPM: true
+#pixiv图片直连,国内需配合代理使用
+pixivDirectConnection: false
+#pixiv图片反代,开启直连后反代服务则无效
+pixivImageProxy: i.pixiv.re
+#每名用户每日次数限制(0 则无限制)
+limit: 30
+
+# Pixiv 登录凭证刷新令牌 (Refresh Token)
+# 获取方法请参考: https://github.com/mixmoe/HibiAPI/issues/53
+refresh_token:
+
+language: zh-cn # 返回语言, 会影响标签的翻译
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/proxy.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/proxy.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f2a0fd8ac8cd41a87005cd25495e713ca1d7b4c9
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/proxy.yaml
@@ -0,0 +1,5 @@
+#代理绝大部分请求
+proxyAddress: http://127.0.0.1:7890
+#开启或关闭使用代理
+switchProxy: false
+
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/setu.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/setu.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..adfdaaf8416126109d40d0e3d9e879ab35e176e3
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/setu.yaml
@@ -0,0 +1,16 @@
+#是否允许私聊使用
+allowPM: true
+#是否排除 AI 作品
+excludeAI: false
+#获取张数大于前面的数时则使用对应的图片大小 可选值: ['mini', 'thumb', 'small', 'regular', 'original']
+imgSize:
+ 6: 'regular'
+ # 9: 'small'
+ # 15: 'thumb'
+#每名用户每日次数限制(0 则无限制)
+limit: 30
+#每个群和私聊的默认设置,单独设置后则失效,时间单位: 秒(s)
+defSet:
+ r18: 0 #1开启0关闭
+ recall: 120 #撤回时间
+ cd: 300
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/state.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/state.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..640112cc3a021405fd69ce806b8aeed68338bd7e
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/state.yaml
@@ -0,0 +1,21 @@
+#网址测试超时时间
+psTestTimeout: 5000
+
+# 测试访问的网址列表(可空)
+# name: 显示名称
+# url: 要访问的网址
+psTestSites: false
+# psTestSites:
+# - name: Baidu
+# url: https://baidu.com
+# - name: Google
+# url: https://google.com
+
+#监控任务
+statusTask: true
+
+#如果出现内存异常的情况可将此配置项开启,如果打开后报错请将监控任务关闭
+statusPowerShellStart: false
+
+#背景图片api 默认https://api.ghser.com/random/pe.php
+backdrop: "https://api.ghser.com/random/pe.php"
diff --git a/Yunzai/plugins/yenai-plugin/config/default_config/whole.yaml b/Yunzai/plugins/yenai-plugin/config/default_config/whole.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..908061a339c045c5b050083430b4d1a1b6ad4292
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/default_config/whole.yaml
@@ -0,0 +1,27 @@
+#群通知类
+groupMessage: false #群消息
+grouptemporaryMessage: false #群临时消息
+groupRecall: false #群撤回
+groupInviteRequest: false #群邀请
+groupAdminChange: false #群管理变动
+groupNumberChange: false #群聊列表变动
+groupMemberNumberChange: false #群成员变动
+addGroupApplication: false #加群申请
+#好友通知类
+privateMessage: false #好友消息
+PrivateRecall: false #好友撤回
+friendRequest: false #好友申请
+friendNumberChange: false #好友列表变动
+#其他通知
+flashPhoto: false #闪照
+botBeenBanned: false #禁言
+input: false #对方正在输入
+#其他设置
+notificationsAll: false #全部通知
+Strangers_love: false #陌生人点赞
+sese: false #涩涩
+state: false #状态
+deltime: 600 #删除缓存
+sesepro: false #涩涩增强
+renderScale: 100 #渲染精度
+anonymous: false #匿名
diff --git a/Yunzai/plugins/yenai-plugin/config/group/.gitignore b/Yunzai/plugins/yenai-plugin/config/group/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..94a2dd146a22340832c88013e9fe92663bb9f2cc
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/group/.gitignore
@@ -0,0 +1 @@
+*.json
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/config/setu/.gitignore b/Yunzai/plugins/yenai-plugin/config/setu/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..94a2dd146a22340832c88013e9fe92663bb9f2cc
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/setu/.gitignore
@@ -0,0 +1 @@
+*.json
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/config/system/gpAdmin_system.js b/Yunzai/plugins/yenai-plugin/config/system/gpAdmin_system.js
new file mode 100644
index 0000000000000000000000000000000000000000..09a28270cb20d4c7914abed2ba3d8301be244c45
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/system/gpAdmin_system.js
@@ -0,0 +1,307 @@
+/*
+* 此配置文件为系统使用,请勿修改,否则可能无法正常使用
+*
+* 如需自定义配置请复制修改上一级help_default.js
+*
+* */
+
+export const helpCfg = {
+ title: '椰奶群管帮助',
+ subTitle: 'Yunzai-Bot & Yenai-Plugin',
+ columnCount: 3,
+ colWidth: 265,
+ theme: 'all',
+ themeExclude: ['default'],
+ style: {
+ fontColor: '#ceb78b',
+ descColor: '#eee',
+ contBgColor: 'rgba(6, 21, 31, .5)',
+ contBgBlur: 3,
+ headerBgColor: 'rgba(6, 21, 31, .4)',
+ rowBgColor1: 'rgba(6, 21, 31, .2)',
+ rowBgColor2: 'rgba(6, 21, 31, .35)'
+ }
+}
+
+export const helpList = [{
+ group: '基础功能',
+ list: [{
+ icon: 1,
+ title: '#禁言 <@QQ> <时间>',
+ desc: '=-='
+ },
+ {
+ icon: 2,
+ title: '#解禁 <@QQ>',
+ desc: '=-='
+ },
+ {
+ icon: 3,
+ title: '#全体禁言|解禁',
+ desc: '顾名思义'
+ },
+ {
+ icon: 16,
+ title: '#发通知 <消息>',
+ desc: '发送@全体的通知'
+ },
+ {
+ icon: 5,
+ title: '#允许|禁止 匿名',
+ desc: '顾名思义'
+ },
+ {
+ title: '#踢 <@QQ>',
+ desc: '顾名思义',
+ icon: 4
+ }, {
+ title: '#发群公告 <文字>',
+ desc: '发送简易公告',
+ icon: 16
+ }, {
+ title: '#查群公告$',
+ desc: '查看现有公告',
+ icon: 3
+ }, {
+ title: '#删群公告 <序号>',
+ desc: '用查看公告获取序号',
+ icon: 4
+ },
+ {
+ title: '#获取禁言列表',
+ desc: '查看本群被禁言的人',
+ icon: 8
+ },
+ {
+ title: '#解除全部禁言',
+ desc: '解除本群全部被禁言的人',
+ icon: 6
+ },
+ {
+ title: '#查看n月没发言的人',
+ desc: '查看多少天|周|月没发言的人',
+ icon: 15
+ },
+ {
+ title: '#清理n天没发言的人',
+ desc: '清理多少天|周|月没发言的人',
+ icon: 14
+ },
+ {
+ title: '#查看从未发言的人',
+ desc: '查看进群后从未发言的人',
+ icon: 1
+ },
+ {
+ title: '#清理从未发言的人',
+ desc: '清理进群后从未发言的人',
+ icon: 5
+ },
+ {
+ title: '#查看不活跃排行榜',
+ desc: '后面可以加数字',
+ icon: 16
+ },
+ {
+ title: '#查看最近入群情况',
+ desc: '后面可以加数字',
+ icon: 4
+ },
+ {
+ title: '#查看加群申请',
+ desc: '查看本群的加群申请',
+ icon: 2
+ },
+ {
+ title: '#同意|拒绝加群申请',
+ desc: '处理本群的加群申请',
+ icon: 19
+ },
+ {
+ title: '#同意|拒绝全部加群申请',
+ desc: '处理本群的全部加群申请',
+ icon: 3
+ },
+ {
+ title: '#我要自闭 <时间>',
+ desc: '自闭一会',
+ icon: 20
+ }]
+}, {
+ group: '字符',
+ list: [
+ {
+ title: '#幸运字符列表',
+ desc: '查看现有字符',
+ icon: 16
+ },
+ {
+ title: '#替换幸运字符+(id)',
+ desc: '用列表获取id',
+ icon: 3
+ },
+ {
+ title: '#抽幸运字符',
+ desc: 'bot抽取字符',
+ icon: 4
+ },
+ {
+ title: '#开启|关闭幸运字符',
+ desc: '=-=',
+ icon: 5
+ }
+ ]
+},
+{
+ group: '定时禁言',
+ list: [
+ {
+ title: '#定时(禁言|解禁)00:00',
+ desc: '设置定时可用cron表达式设置',
+ icon: 12
+ }, {
+ title: '#定时禁言任务',
+ desc: '查看禁言任务',
+ icon: 10
+ }, {
+ title: '#取消定时(禁言|解禁)',
+ desc: '取消查看禁言任务',
+ icon: 3
+ }
+ ]
+},
+{
+ group: '群信息',
+ list: [
+ {
+ icon: 2,
+ title: '#群星级',
+ desc: '查看群星级'
+ },
+ {
+ title: '#今天谁生日',
+ desc: '今天可换为昨天或后天或日期',
+ icon: 12
+ }, {
+ title: '#哪个叼毛是龙王',
+ desc: '查看谁是龙王',
+ icon: 6
+ }, {
+ title: '#今日打卡',
+ desc: '查看今日打卡',
+ icon: 5
+ }, {
+ title: '#群数据(7天)?',
+ desc: '活跃数据等',
+ icon: 7
+ }, {
+ title: '#群发言榜单(7天)?',
+ desc: '不加7天查看昨天的数据',
+ icon: 16
+ }
+ ]
+},
+{
+ group: '其他',
+ list: [{
+ title: '#开启/关闭加群通知',
+ desc: '将加群申请发送至群',
+ icon: 2
+ }]
+},
+{
+ group: '进群验证(更多设置请在config/groupverify.yaml进行设置)',
+ list: [
+ {
+ title: '#开启验证',
+ desc: '开启本群验证',
+ icon: 4
+ },
+ {
+ title: '#关闭验证',
+ desc: '关闭本群验证',
+ icon: 15
+ },
+ {
+ title: '#重新验证 <@群员>',
+ desc: '重新发起验证',
+ icon: 1
+ }, {
+ title: '#绕过验证 <@群员>',
+ desc: '绕过本次验证',
+ icon: 3
+ },
+ {
+ title: '#切换验证模式',
+ desc: '更换答案匹配模式',
+ icon: 2
+ },
+ {
+ title: '#设置验证超时时间+(s)',
+ desc: '多少秒后踢出',
+ icon: 17
+ }]
+}, {
+ group: '违禁词',
+ list: [
+ {
+ title: '#新增违禁词.*',
+ desc: '文档查看具体用法',
+ icon: 7
+ },
+ {
+ title: '#删除违禁词.*',
+ desc: '---',
+ icon: 3
+ },
+ {
+ title: '#查看违禁词.*',
+ desc: '---',
+ icon: 9
+ },
+ {
+ title: '#违禁词列表',
+ desc: '列表',
+ icon: 17
+ },
+ {
+ title: '#设置违禁词禁言时间400',
+ desc: '禁言时间',
+ icon: 11
+ }]
+}, {
+ group: 'Bot为群主可用',
+ list: [
+ {
+ title: '#设置管理 <@QQ>',
+ desc: '增加管理',
+ icon: 8
+ },
+ {
+ title: '#取消管理 <@QQ> ',
+ desc: '=-=',
+ icon: 9
+ },
+ {
+ title: '#申请头衔 <头衔>',
+ desc: '群员自己设置',
+ icon: 19
+ },
+ {
+ title: '#修改头衔 <@QQ> <头衔>',
+ desc: '主人给别人设置',
+ icon: 10
+ },
+ {
+ title: '#(增加|减少|查看)头衔屏蔽词',
+ desc: '头衔屏蔽词',
+ icon: 2
+ },
+ {
+ title: '#切换头衔屏蔽词匹配模式',
+ desc: '模糊匹配和精确匹配',
+ icon: 13
+ }]
+}]
+
+export const isSys = true
diff --git a/Yunzai/plugins/yenai-plugin/config/system/help_system.js b/Yunzai/plugins/yenai-plugin/config/system/help_system.js
new file mode 100644
index 0000000000000000000000000000000000000000..3773f848eca6bd1540d08489a9b80166b4ea7fee
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/system/help_system.js
@@ -0,0 +1,295 @@
+/*
+* 此配置文件为系统使用,请勿修改,否则可能无法正常使用
+*
+* 如需自定义配置请复制修改上一级help_default.js
+*
+* */
+
+export const helpCfg = {
+ title: '椰奶帮助',
+ subTitle: 'Yunzai-Bot & Yenai-Plugin',
+ columnCount: 3,
+ colWidth: 265,
+ theme: 'all',
+ themeExclude: ['default'],
+ style: {
+ fontColor: '#ceb78b',
+ descColor: '#eee',
+ contBgColor: 'rgba(6, 21, 31, .5)',
+ contBgBlur: 3,
+ headerBgColor: 'rgba(6, 21, 31, .4)',
+ rowBgColor1: 'rgba(6, 21, 31, .2)',
+ rowBgColor2: 'rgba(6, 21, 31, .35)'
+ }
+}
+
+export const helpList = [{
+ group: 'Bot相关',
+ auth: 'master',
+ list: [{
+ icon: 1,
+ title: '#发好友 <消息>',
+ desc: '给好友发送一条涩涩的消息'
+ },
+ {
+ icon: 2,
+ title: '#发群聊 <群号> <消息>',
+ desc: '给群聊发送一条涩涩的消息'
+ },
+ {
+ icon: 3,
+ title: '#改头像 <图片>',
+ desc: '顾名思义'
+ },
+ {
+ icon: 4,
+ title: '#改状态 <状态> ',
+ desc: '顾名思义'
+ },
+ {
+ icon: 5,
+ title: '#改昵称 <昵称> ',
+ desc: '顾名思义'
+ },
+ {
+ icon: 6,
+ title: '#改签名 <签名> ',
+ desc: '顾名思义'
+ },
+ {
+ title: '#改性别 <性别> ',
+ desc: '顾名思义',
+ icon: 7
+ },
+ {
+ title: '#改群名片 <名片> ',
+ desc: '群里Bot自己的名片',
+ icon: 8
+ },
+ {
+ title: '#改群昵称 <昵称>',
+ desc: '改群的昵称',
+ icon: 9
+ },
+ {
+ title: '#改群头像 <图片>',
+ desc: '顾名思义',
+ icon: 10
+ },
+ {
+ title: '#删好友 ',
+ desc: '删掉涩涩的好友',
+ icon: 11
+ },
+ {
+ title: '#退群 <群号> ',
+ desc: '退掉涩涩的群',
+ icon: 12
+ },
+ {
+ title: '#获取群列表',
+ desc: '获取Bot的所有群',
+ icon: 13
+ },
+ {
+ title: '#获取好友列表',
+ desc: '获取Bot的所有好友',
+ icon: 14
+ },
+ {
+ title: '#取说说列表 <页数> ',
+ desc: '获取Bot的说说列表',
+ icon: 15
+ },
+ {
+ title: '#发说说 <内容> ',
+ desc: '发送一条涩涩的说说',
+ icon: 16
+ },
+ {
+ title: '#删说说 <序号>',
+ desc: '用取说说列表获取序号',
+ icon: 17
+ },
+ {
+ title: '#清空说说',
+ desc: '一键清空',
+ icon: 18
+ },
+ {
+ title: '#清空留言',
+ desc: '一键清空留言',
+ icon: 19
+ }, {
+ title: '#开启|关闭戳一戳',
+ desc: 'QQ的戳一戳开关',
+ icon: 5
+ }, {
+ title: '#同意|拒绝全部好友申请',
+ desc: '顾名思义',
+ icon: 6
+ }, {
+ title: '#查看好友申请',
+ desc: '查看现有好友申请',
+ icon: 1
+ },
+ {
+ title: '同意|拒绝好友申请 ',
+ desc: '同意或拒绝好友申请',
+ icon: 18
+ },
+ {
+ title: '#查看群邀请',
+ desc: '查看现有群邀请',
+ icon: 3
+ }, {
+ title: '#同意|拒绝全部群邀请',
+ desc: '同意或拒绝全部群邀请',
+ icon: 15
+ }, {
+ title: '#同意|拒绝群邀请 <群号>',
+ desc: '同意或拒绝全部群邀请',
+ icon: 7
+ }, {
+ title: '#查看全部请求',
+ desc: '查看所有请求',
+ icon: 20
+ }, {
+ title: '#(开启|关闭)好友添加',
+ desc: '是否开启好友添加',
+ icon: 7
+ }, {
+ title: '#更改好友申请方式[0123]',
+ desc: '带0参数为帮助',
+ icon: 12
+ }, {
+ title: '#拉黑 #取消拉黑',
+ desc: '可带at或直接键入qq,拉黑后面可带"群"',
+ icon: 13
+ }]
+},
+{
+ group: '娱乐功能',
+ list: [
+ {
+ icon: 7,
+ title: '#椰羊收益曲线',
+ desc: '查看角色收益曲线'
+ },
+ {
+ icon: 13,
+ title: '#椰羊参考面板',
+ desc: '查看角色参考面板'
+ },
+ {
+ icon: 9,
+ title: '#收益曲线帮助',
+ desc: '=-='
+ }, {
+ icon: 20,
+ title: '#唱歌',
+ desc: '随机唱鸭'
+ },
+ {
+ icon: 13,
+ title: '#赞我',
+ desc: '给你点一个大大的赞'
+ },
+ {
+ icon: 15,
+ title: '#支付宝到账<数字>',
+ desc: '听到账爽一下'
+ }, {
+ icon: 17,
+ title: '#翻译',
+ desc: '有道翻译'
+ }, {
+ icon: 9,
+ title: '#搜索菜单',
+ desc: '各大引擎搜索'
+ }, {
+ icon: 1,
+ title: '#半次元话题',
+ desc: '=-='
+ }, {
+ icon: 7,
+ title: '#铃声搜索',
+ desc: '铃声多多'
+ }, {
+ icon: 1,
+ title: '#bgg搜索<关键词>',
+ desc: '桌游搜索'
+ }, {
+ icon: 19,
+ title: '#bgg排行',
+ desc: '桌游排行'
+ }]
+},
+{
+ group: '搜图搜番',
+ list: [
+ {
+ title: '#搜图',
+ desc: '默认SauceNAO',
+ icon: 10
+ },
+ {
+ title: '#搜番',
+ desc: 'WhatAnime',
+ icon: 6
+ },
+ {
+ title: '#(SauceNAO|sn)搜图',
+ desc: 'SauceNAO',
+ icon: 1
+ },
+ {
+ title: '#(Ascii2D|ac)搜图',
+ desc: 'Ascii2D',
+ icon: 5
+ },
+ {
+ title: '#设置SauceNAOApiKey',
+ desc: 'SauceNAOApiKey',
+ icon: 9
+ }
+ ]
+},
+{
+ group: '设置,版本相关',
+ auth: 'master',
+ list: [{
+ icon: 8,
+ title: '#椰奶设置',
+ desc: '查看椰奶设置'
+ },
+ {
+ icon: 1,
+ title: '#椰奶(强制)更新',
+ desc: '更新椰奶'
+ },
+ {
+ icon: 15,
+ title: '#椰奶版本',
+ desc: '查看版本信息'
+ },
+ {
+ icon: 12,
+ title: '#椰奶更新日志',
+ desc: '查看更新日志'
+ }, {
+ icon: 8,
+ title: '#椰奶状态(pro)?',
+ desc: '查看系统状态'
+ }, {
+ icon: 3,
+ title: '#椰奶群管帮助',
+ desc: '群管帮助'
+ }, {
+ icon: 12,
+ title: '#椰奶(启|禁)用全部通知',
+ desc: '一键启用或禁用全部通知'
+ }]
+}]
+
+export const isSys = true
diff --git a/Yunzai/plugins/yenai-plugin/config/system/sese_system.js b/Yunzai/plugins/yenai-plugin/config/system/sese_system.js
new file mode 100644
index 0000000000000000000000000000000000000000..5589452d2523997f838cae1b2c5ff13b539f3dcd
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/config/system/sese_system.js
@@ -0,0 +1,138 @@
+
+/** 涩涩帮助 */
+export const helpCfg = {
+ title: '椰奶涩涩帮助',
+ subTitle: 'Yunzai-Bot & Yenai-Plugin',
+ columnCount: 3,
+ colWidth: 265,
+ theme: 'all',
+ themeExclude: ['default'],
+ style: {
+ fontColor: '#ceb78b',
+ descColor: '#eee',
+ contBgColor: 'rgba(6, 21, 31, .5)',
+ contBgBlur: 3,
+ headerBgColor: 'rgba(6, 21, 31, .4)',
+ rowBgColor1: 'rgba(6, 21, 31, .2)',
+ rowBgColor2: 'rgba(6, 21, 31, .35)'
+ }
+}
+
+export const helpList = [{
+ group: 'Pixiv',
+ list: [{
+ icon: 1,
+ title: '#无内鬼 #setu',
+ desc: 'luoli接口随机图片'
+ },
+ {
+ icon: 2,
+ title: '#椰奶tag <关键词*3>',
+ desc: 'luoli接口搜索tag'
+ },
+ {
+ icon: 3,
+ title: '#来(n)张好康的',
+ desc: '国内镜像站接口,比较健康'
+ },
+ {
+ icon: 4,
+ title: '#pximg(pro)?',
+ desc: '随机图片'
+ },
+ {
+ icon: 5,
+ title: '#查看热门tag',
+ desc: '顾名思义'
+ },
+ {
+ icon: 6,
+ title: '#Pid搜图 ',
+ desc: '图片详情信息'
+ },
+ {
+ title: '#tag(pro)搜图 <关键词>',
+ desc: '不加Pro为国内镜像站接口',
+ icon: 7
+ },
+ {
+ title: '#Uid搜图 ',
+ desc: '搜索画师插画',
+ icon: 8
+ },
+ {
+ title: '#相关作品 ',
+ desc: '作品的相关作品',
+ icon: 9
+ },
+ {
+ title: '#看看<类型>榜',
+ desc: 'Pixiv榜单',
+ icon: 10
+ },
+ {
+ title: '#来(n)?张推荐图',
+ desc: '登录后使用',
+ icon: 19
+ },
+ {
+ title: '#pixiv登录信息',
+ desc: '登录后使用',
+ icon: 19
+ }
+ ]
+},
+{
+ group: '哔咔',
+ list: [
+ {
+ icon: 7,
+ title: '#哔咔搜索<关键词>',
+ desc: '更多使用请查看文档'
+ },
+ {
+ icon: 13,
+ title: '#哔咔id(第n页)?(第n话)?',
+ desc: '查看作品详情'
+ },
+ {
+ icon: 9,
+ title: '#哔咔类别列表',
+ desc: '适用于类别搜索'
+ }, {
+ icon: 20,
+ title: '#哔咔看<1~20>',
+ desc: '搜索后使用'
+ },
+ {
+ icon: 13,
+ title: '#哔咔下一页',
+ desc: '快速翻页'
+ },
+ {
+ icon: 15,
+ title: '#哔咔下一话',
+ desc: '快速下一话'
+ }]
+},
+{
+ group: '其他',
+ list: [
+ {
+ icon: 15,
+ title: '#coser',
+ desc: '养眼=-='
+ }, {
+ title: '#acg刻晴',
+ desc: 'acgcos',
+ icon: 9
+ },
+ {
+ title: '#来点xxx',
+ desc: 'xxx',
+ icon: 1
+ }
+ ]
+}]
+
+export const isSys = true
diff --git "a/Yunzai/plugins/yenai-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt" "b/Yunzai/plugins/yenai-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt"
new file mode 100644
index 0000000000000000000000000000000000000000..e67fd6eb9b23b9cd6761f1ef048d1e43dd04e2ec
--- /dev/null
+++ "b/Yunzai/plugins/yenai-plugin/config/system/\350\257\267\345\213\277\344\277\256\346\224\271\346\255\244\347\233\256\345\275\225\344\270\213\347\232\204\346\226\207\344\273\266.txt"
@@ -0,0 +1,3 @@
+此目录为系统配置目录
+请勿修改此目录下的文件,否则可能导致工作不正常
+如需配置,可配置上级目录,复制对应_default.js 文件进行配置
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/constants/fun.js b/Yunzai/plugins/yenai-plugin/constants/fun.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e1880299789e971693cb32b914353e67e2cbc14
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/fun.js
@@ -0,0 +1,119 @@
+/** 点赞成功回复的图片 */
+export const successImgs = [
+ 'https://xiaobai.klizi.cn/API/ce/xin.php?qq=',
+ 'https://xiaobai.klizi.cn/API/ce/zan.php?qq='
+]
+
+/** 点赞失败回复的图片 */
+export const faildsImgs = [
+ 'https://xiaobai.klizi.cn/API/ce/paa.php?qq='
+]
+
+export const heisiType = {
+ '白丝': { type: 'baisi', page: 17 },
+ '黑丝': { type: 'heisi', page: 43 },
+ '巨乳': { type: 'juru', page: 8 },
+ 'jk': { type: 'jk', page: 6 },
+ '网红': { type: 'mcn', page: 36 },
+ '美足': { type: 'meizu', page: 9 }
+}
+
+export const xiurenTypeId = {
+ '秀人': {
+ id: 117,
+ maxPage: 88
+ },
+ '足控': {
+ id: 229,
+ maxPage: 8
+ },
+ '雅拉伊': {
+ id: 306,
+ maxPage: 18
+ }
+}
+
+export const pandadiuType = {
+ '制服': {
+ id: 66,
+ page: 8
+ },
+ '写真': {
+ id: 65,
+ page: 55
+ },
+ 'cos': {
+ id: 30,
+ page: 210
+ },
+ '正片': {
+ id: 31,
+ page: 187
+ },
+ '场照': {
+ id: 75,
+ page: 23
+ }
+}
+
+export const youDaoLangType = [{
+ code: 'ar',
+ label: '阿拉伯语',
+ alphabet: 'A'
+}, {
+ code: 'de',
+ label: '德语',
+ alphabet: 'D'
+}, {
+ code: 'ru',
+ label: '俄语',
+ alphabet: 'E'
+}, {
+ code: 'fr',
+ label: '法语',
+ alphabet: 'F'
+}, {
+ code: 'ko',
+ label: '韩语',
+ alphabet: 'H'
+}, {
+ code: 'nl',
+ label: '荷兰语',
+ alphabet: 'H'
+}, {
+ code: 'pt',
+ label: '葡萄牙语',
+ alphabet: 'P'
+}, {
+ code: 'ja',
+ label: '日语',
+ alphabet: 'R'
+}, {
+ code: 'th',
+ label: '泰语',
+ alphabet: 'T'
+}, {
+ code: 'es',
+ label: '西班牙语',
+ alphabet: 'X'
+}, {
+ code: 'en',
+ label: '英语',
+ alphabet: 'Y'
+}, {
+ code: 'it',
+ label: '意大利语',
+ alphabet: 'Y'
+}, {
+ code: 'vi',
+ label: '越南语',
+ alphabet: 'Y'
+}, {
+ code: 'id',
+ label: '印度尼西亚语',
+ alphabet: 'Y'
+}, {
+ code: 'zh-CHS',
+ label: '中文',
+ alphabet: 'Z'
+}]
diff --git a/Yunzai/plugins/yenai-plugin/constants/msg.js b/Yunzai/plugins/yenai-plugin/constants/msg.js
new file mode 100644
index 0000000000000000000000000000000000000000..66654403052db54c445b5a90021749df95d53405
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/msg.js
@@ -0,0 +1,67 @@
+export const setuMsg = {
+ start: [
+ '正在给你找setu了,你先等等再冲~',
+ '你先别急,正在找了~',
+ '马上去给你找涩图,你先憋一会~',
+ '奴家马上去给你找瑟瑟的图片~'
+ ],
+ cd: [
+ '你这么喜欢色图,还不快点冲!',
+ '你的色图不出来了!',
+ '注意身体,色图看多了对身体不太好',
+ '憋住,不准冲!',
+ '憋再冲了!',
+ '呃...好像冲了好多次...感觉不太好呢...',
+ '憋冲了!你已经冲不出来了!',
+ '你急啥呢?',
+ '你是被下半身控制了大脑吗?'
+ ],
+ send: [
+ '给大佬递图',
+ '这是你的🐍图',
+ '你是大色批',
+ '看!要色图的色批出现了!',
+ '?',
+ '喏,图',
+ '给给给个🐍图',
+ '色图有我好冲吗?',
+ '呐呐呐,欧尼酱别看色图了呐',
+ '有什么好色图有给发出来让大伙看看!',
+ '没有,有也不给(骗你的~)',
+ '天天色图色图的,今天就把你变成色图!',
+ '咱没有色图(骗你的~)',
+ '哈?你的脑子一天都在想些什么呢,咱才没有这种东西啦。',
+ '呀!不要啊!等一...下~',
+ '呜...不要啦!太色了咱~',
+ '不要这样子啦(*/ω\*)',
+ 'Hen....Hentai!。',
+ '讨....讨厌了(脸红)',
+ '你想...想做什么///',
+ '啊.....你...你要干什么?!走开.....走开啦大hentai!一巴掌拍飞!(╯‵□′)╯︵┻━┻',
+ '变态baka死宅?',
+ '已经可以了,现在很多死宅也都没你这么恶心了',
+ '噫…你这个死变态想干嘛!居然想叫咱做这种事,死宅真恶心!快离我远点,我怕你污染到周围空气了(嫌弃脸)',
+ '这么喜欢色图呢?不如来点岛风色图?',
+ 'hso!',
+ '这么喜欢看色图哦?变态?',
+ 'eee,死肥宅不要啦!恶心心!'
+ ]
+}
+
+export const pixivMsg = {
+ start: [
+ '你先别急,正在给你搜了(。-ω-)zzz',
+ '你先别急,马上去给你找哦ε(*´・ω・)з',
+ '你先别急,正在给你搜了(。-ω-)zzz',
+ '你先别急,马上去给你找哦ε(*´・ω・)з'
+ ]
+}
+
+export const groupTitleMsg = [
+ '换上辣(´•ω•̥`)',
+ '嗯!不戳的头衔哦٩(๑•ㅂ•)۶',
+ '给你换上了哦(*^ワ^*)',
+ '又要换了吗,真是喜新厌旧呢( •̥́ ˍ •̀ू )',
+ '啾咪٩(๑•̀ω•́๑)۶',
+ '弃旧恋新了么笨蛋( 。ớ ₃ờ)ھ'
+]
diff --git a/Yunzai/plugins/yenai-plugin/constants/nga.js b/Yunzai/plugins/yenai-plugin/constants/nga.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbbb51ffee5b3663b1c0c2a13b9ccf381cdfc982
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/nga.js
@@ -0,0 +1,74 @@
+export const incomeCurve = {
+ 帮助: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-j5voXxZ96T3cS1di-q9.png',
+ 烟绯: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-gz71XxZ96T3cS1di-q9.png',
+ 辛焱: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-1uboXyZ9cT3cS1di-q9.png',
+ 宵宫: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-acsfXyZ9eT3cS1di-q9.png',
+ 香菱: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-akwxXwZ8wT3cS1di-q9.png',
+ 托马: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-in5cXwZ90T3cS1di-q9.png',
+ 胡桃: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-6vbsXvZ8pT3cS1di-q9.png',
+ 迪卢克: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-dgbbXxZ92T3cS1di-q9.png',
+ 安柏: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-8m6vXxZ91T3cS1di-q9.png',
+ 夜兰: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-3oq4XxZ95T3cS1di-q9.png',
+ 行秋: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-b18cXwZ91T3cS1di-q9.png',
+ 神里绫人: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-hyagXyZ9fT3cS1di-q9.png',
+ 珊瑚宫心海: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-3ktjXxZ9bT3cS1di-q9.png',
+ 莫娜: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-9cifXyZ9bT3cS1di-q9.png',
+ 达达利亚: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-hu24XyZ9cT3cS1di-q9.png',
+ 芭芭拉: 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-16o0XtZ7yT3cS1di-q9.png',
+ 可莉: 'https://img.nga.178.com/attachments/mon_202208/17/i2Q2q-bplpXwZ8zT3cS1di-q9.png',
+ 班尼特: 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-ggrvXsZ7sT3cS1di-q9.png',
+ 重云: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-al2oXxZ9bT3cS1di-q9.png',
+ 优菈: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-ec2aXxZ98T3cS1di-q9.png',
+ 神里绫华: 'https://img.nga.178.com/attachments/mon_202303/27/i2Q8sgk-k1u4XxZ99T3cS1di-q9.png',
+ 申鹤: 'https://img.nga.178.com/attachments/mon_202303/27/i2Q8sgk-j2z6XtZ81T3cS1di-q9.png',
+ 七七: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-gbmkXxZ99T3cS1di-q9.png',
+ 罗莎莉亚: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-2tppXyZ9cT3cS1di-q9.png',
+ 凯亚: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-cpsdXxZ96T3cS1di-q9.png',
+ 甘雨: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-jh27XxZ96T3cS1di-q9.png',
+ 迪奥娜: 'https://img.nga.178.com/attachments/mon_202303/27/i2Q8sgk-9xe5XtZ80T3cS1di-q9.png',
+ 埃洛伊: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-a90bXwZ8yT3cS1di-q9.png',
+ 钟离: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-3ifiXwZ8zT3cS1di-q9.png',
+ 云堇: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-9yzvXxZ97T3cS1di-q9.png',
+ 五郎: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-j6rfXxZ9aT3cS1di-q9.png',
+ 诺艾尔: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-9ht1XxZ97T3cS1di-q9.png',
+ 凝光: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-3sa1XxZ94T3cS1di-q9.png',
+ 岩主: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-kje0XxZ92T3cS1di-q9.png',
+ 荒泷一斗: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-73zhXxZ97T3cS1di-q9.png',
+ 阿贝多: 'https://img.nga.178.com/attachments/mon_202208/19/i2Q2q-cwmhXwZ8wT3cS1di-q9.png',
+ 早柚: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-28j7XxZ94T3cS1di-q9.png',
+ 魈: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-htbXwZ8yT3cS1di-q9.png',
+ 琴: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-kqstXxZ9aT3cS1di-q9.png',
+ 鹿野院平藏: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-jx1yXxZ92T3cS1di-q9.png',
+ 雷主: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-aqakXxZ93T3cS1di-q9.png',
+ 雷泽: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-axdiXxZ97T3cS1di-q9.png',
+ 雷电将军: [
+ 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-kszoXyZ9eT3cS1di-q9.png',
+ 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-ei3cXyZ9fT3cS1di-q9.png'
+ ],
+ 九条裟罗: 'https://img.nga.178.com/attachments/mon_202208/21/i2Qjk1-ep0dXwZ8yT3cS1di-q9.png',
+ 提纳里: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-1twzXwZ8uT3cS1di-q9.png',
+ 草主: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-620hXuZ8aT3cS1di-q9.png',
+ 枫原万叶: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-i5niXvZ8iT3cS1di-q9.png',
+ 丽莎: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-ba0sXxZ96T3cS1di-q9.png',
+ 刻晴: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-j403XyZ9hT3cS1di-q9.png',
+ 久岐忍: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-1zzuXxZ97T3cS1di-q9.png',
+ 菲谢尔: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-77grXxZ98T3cS1di-q9.png',
+ 北斗: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-5xbkZ2dT3cS1di-q9.png',
+ 八重神子: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-ddaeXyZ9kT3cS1di-q9.png',
+ 多莉: 'https://img.nga.178.com/attachments/mon_202209/09/i2Q181-45azXyZ9bT3cS1di-q9.png',
+ 柯莱: 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-a7huXsZ7wT3cS1di-q9.png',
+ 温迪: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-2s69XwZ8uT3cS1di-q9.png',
+ 砂糖: 'https://img.nga.178.com/attachments/mon_202303/27/i2Q8sgk-6rx4XtZ81T3cS1di-q9.png',
+ 风主: 'https://img.nga.178.com/attachments/mon_202208/24/i2Q8oyf-bplhXvZ8lT3cS1di-q9.png',
+ 坎蒂丝: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-jknyXxZ98T3cS1di-q9.png',
+ 赛诺: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-i3a5X10Z9vT3cS1di-q9.png',
+ 妮露: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-7njbXuZ8aT3cS1di-q9.png',
+ 纳西妲: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-klw9Z2pT3cS1di-q9.png',
+ 莱依拉: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-p52XuZ8bT3cS1di-q9.png',
+ 珐露珊: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-cf75XuZ87T3cS1di-q9.png',
+ 流浪者: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-71e3XtZ87T3cS1di-q9.png',
+ 艾尔海森: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-4ntzXuZ8fT3cS1di-q9.png',
+ 瑶瑶: 'https://img.nga.178.com/attachments/mon_202302/07/i2Q180-a6gvXtZ82T3cS1di-q9.png',
+ 迪希雅: 'https://img.nga.178.com/attachments/mon_202303/05/i2Qjr7-iq98XtZ85T3cS1di-q9.png',
+ 米卡: 'https://img.nga.178.com/attachments/mon_202303/27/i2Q8sgk-5qquXtZ7zT3cS1di-q9.png'
+}
diff --git a/Yunzai/plugins/yenai-plugin/constants/other.js b/Yunzai/plugins/yenai-plugin/constants/other.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef694c0d5905b109acc82241b3041fe78177dd91
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/other.js
@@ -0,0 +1,46 @@
+/** 时间单位 */
+export const Time_unit = {
+ 毫秒: 0.001,
+ 秒: 1,
+ S: 1,
+ SECOND: 1,
+ 分: 60,
+ 分钟: 60,
+ M: 60,
+ MIN: 60,
+ MINUTE: 60,
+ 时: 3600,
+ 小时: 3600,
+ H: 3600,
+ HOUR: 3600,
+ 天: 86400,
+ 日: 86400,
+ D: 86400,
+ DAY: 86400,
+ 周: 604800,
+ W: 604800,
+ WEEK: 604800,
+ 月: 2592000,
+ MONTH: 2592000,
+ 年: 31536000,
+ Y: 31536000,
+ YEAR: 31536000
+
+}
+
+/** 在线状态 */
+export const status = {
+ 31: '离开',
+ 50: '忙碌',
+ 70: '请勿打扰',
+ 41: '隐身',
+ 11: '我在线上',
+ 60: 'Q我吧'
+}
+
+/** 权限 */
+export const ROLE_MAP = {
+ admin: '群管理',
+ owner: '群主',
+ member: '群员'
+}
diff --git a/Yunzai/plugins/yenai-plugin/constants/pixiv.js b/Yunzai/plugins/yenai-plugin/constants/pixiv.js
new file mode 100644
index 0000000000000000000000000000000000000000..814b196084162a6a9fd2fa2c347f4107b745034d
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/pixiv.js
@@ -0,0 +1,89 @@
+export const rankType = {
+ 日: {
+ type: 'day',
+ total: 500,
+ r18: {
+ total: 100,
+ type: 'day_r18'
+ }
+ },
+ 周: {
+ type: 'week',
+ total: 500,
+ r18: {
+ total: 100,
+ type: 'week_r18'
+ }
+ },
+ 月: {
+ type: 'month',
+ total: 500,
+ r18: false
+ },
+ AI: {
+ type: 'day_ai',
+ total: 50,
+ r18: {
+ total: 50,
+ type: 'day_r18_ai'
+ }
+ },
+ 男性向: {
+ type: 'day_male',
+ total: 500,
+ r18: {
+ total: 300,
+ type: 'day_male_r18'
+ }
+ },
+ 女性向: {
+ type: 'day_female',
+ total: 500,
+ r18: {
+ total: 300,
+ type: 'day_female_r18'
+ }
+ },
+ 漫画日: {
+ type: 'day_manga',
+ total: 500,
+ r18: {
+ total: 100,
+ type: 'day_r18_manga'
+ }
+ },
+ 漫画周: {
+ type: 'week_manga',
+ total: 500,
+ r18: {
+ total: 100,
+ type: 'week_r18_manga'
+ }
+ },
+ 漫画月: {
+ type: 'month_manga',
+ total: 500,
+ r18: false
+ },
+ 漫画新人周: {
+ type: 'week_rookie_manga',
+ total: 500,
+ r18: false
+ },
+ 新人: {
+ type: 'week_rookie',
+ total: 500,
+ r18: false
+ },
+ 原创: {
+ type: 'week_original',
+ total: 500,
+ r18: false
+ }
+}
+export const ImageRPSS = [
+ 'i.pixiv.re',
+ 'proxy.pixivel.moe',
+ 'px2.rainchan.win',
+ 'sex.nyan.xyz'
+]
diff --git a/Yunzai/plugins/yenai-plugin/constants/search.js b/Yunzai/plugins/yenai-plugin/constants/search.js
new file mode 100644
index 0000000000000000000000000000000000000000..47d5429199bf148a885375419900e4fe50eb6c10
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/constants/search.js
@@ -0,0 +1,56 @@
+export const SEARCH_MAP = {
+
+ 百度: 'https://www.baidu.com/s?wd=',
+
+ 必应: 'https://cn.bing.com/search?q=',
+
+ 谷歌: 'https://www.google.com/search?q=',
+
+ 微博: 'https://s.weibo.com/weibo?q=',
+
+ 淘宝: 'https://s.taobao.com/search?q=',
+
+ 京东: 'https://search.jd.com/Search?keyword=',
+
+ 知乎: 'https://www.zhihu.com/search?q=',
+
+ 头条: 'https://so.toutiao.com/search?keyword=',
+
+ 抖音: 'https://www.douyin.com/search/',
+
+ 快手: 'https://www.kuaishou.com/search/video?searchKey=',
+
+ 虎牙: 'https://www.huya.com/search?hsk=',
+
+ 斗鱼: 'https://www.douyu.com/search/?kw=',
+
+ 萌娘百科: 'https://zh.moegirl.org.cn/index.php?search=',
+
+ B站: 'https://search.bilibili.com/all?keyword=',
+
+ 腾讯视频: 'https://v.qq.com/x/search/?q=',
+
+ 优酷: 'https://so.youku.com/search_video/',
+
+ 爱奇艺: 'https://so.iqiyi.com/so/q_',
+
+ 芒果TV: 'https://so.mgtv.com/so?k=',
+
+ 百度图片: 'https://image.baidu.com/search/index?tn=baiduimage&word=',
+
+ 百度文库: 'https://wenku.baidu.com/search?word=',
+
+ 4399: 'https://so2.4399.com/search/search.php?k=',
+
+ GitHub: 'https://github.com/search?q=',
+
+ 力扣: 'https://leetcode.cn/search/?q=',
+
+ MDN: 'https://developer.mozilla.org/zh-CN/search?q=',
+
+ CSDN: 'https://so.csdn.net/so/search?q=',
+
+ 掘金: 'https://juejin.cn/search?query=',
+
+ 油猴: 'https://greasyfork.org/zh-CN/scripts?q='
+}
diff --git a/Yunzai/plugins/yenai-plugin/guoba.support.js b/Yunzai/plugins/yenai-plugin/guoba.support.js
new file mode 100644
index 0000000000000000000000000000000000000000..898540ef77e7eadd2d5ec8493e2727b3660cf217
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/guoba.support.js
@@ -0,0 +1,387 @@
+import { Config } from './components/index.js'
+/**
+ * 支持锅巴
+ * 锅巴插件:https://gitee.com/guoba-yunzai/guoba-plugin.git
+ * 组件类型,可参考 https://vvbin.cn/doc-next/components/introduction.html
+ * https://antdv.com/components/overview-cn/
+ */
+const Path = process.cwd()
+const Plugin_Path = `${Path}/plugins/yenai-plugin`
+
+export function supportGuoba () {
+ return {
+ pluginInfo: {
+ name: 'yenai-plugin',
+ title: 'Yenai-Plugin',
+ author: '@椰羊',
+ authorLink: 'https://gitee.com/yeyang52',
+ link: 'https://gitee.com/yeyang52/yenai-plugin',
+ isV3: true,
+ isV2: false,
+ description: '提供对Bot的一些便捷操作',
+ // 显示图标,此为个性化配置
+ // 图标可在 https://icon-sets.iconify.design 这里进行搜索
+ // icon: 'emojione-monotone:baby-chick',
+ // 图标颜色,例:#FF0000 或 rgb(255, 0, 0)
+ // iconColor: '#ffff99',
+ // 如果想要显示成图片,也可以填写图标路径(绝对路径)
+ iconPath: `${Plugin_Path}/resources/img/tb.png`
+ },
+ // 配置项信息
+ configInfo: {
+ // 配置项 schemas
+ schemas: [
+ {
+ component: 'whole.Divider',
+ label: '消息通知'
+ },
+ {
+ field: 'whole.privateMessage',
+ label: '好友消息',
+ bottomHelpMessage: '开启后将转发好友消息,可进行回复',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.groupMessage',
+ label: '群聊消息',
+ helpMessage: '开启后将转发全部群聊消息,建议配置单独群开启',
+ bottomHelpMessage: '是否开启群聊消息通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.grouptemporaryMessage',
+ label: '群临时消息',
+ bottomHelpMessage: '开启后将转发群临时消息',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.groupRecall',
+ label: '群聊撤回',
+ bottomHelpMessage: '群聊撤回后将撤回的消息转发给主人',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.PrivateRecall',
+ label: '好友撤回',
+ bottomHelpMessage: '好友私聊撤回后将撤回的消息转发给主人',
+ component: 'Switch'
+ },
+ {
+ component: 'Divider',
+ label: '申请通知'
+ },
+ {
+ field: 'whole.friendRequest',
+ label: '好友申请',
+ helpMessage: '将云崽的自动同意好友申请关闭后,可回复同意或拒绝进行处理',
+ bottomHelpMessage: '是否开启好友申请通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.addGroupApplication',
+ label: '加群申请',
+ helpMessage: '可回复同意或拒绝进行处理',
+ bottomHelpMessage: '是否开启加群申请通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.groupInviteRequest',
+ label: '群聊邀请',
+ helpMessage: '将云崽的自动退群设置为0后,可回复同意或拒绝进行处理',
+ bottomHelpMessage: '是否开启群聊邀请通知',
+ component: 'Switch'
+ },
+ {
+ component: 'Divider',
+ label: '列表变动'
+ },
+ {
+ field: 'whole.groupAdminChange',
+ label: '群管理变动',
+ bottomHelpMessage: 'Bot被设置或取消管理,群员被设置或取消管理通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.friendNumberChange',
+ label: '好友列表变动',
+ bottomHelpMessage: '新增好友和好友减少通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.groupNumberChange',
+ label: '群聊列表变动',
+ bottomHelpMessage: '群转让,新增群聊,Bot退群,Bot被踢,群员被踢等通知',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.groupMemberNumberChange',
+ label: '群成员变动',
+ bottomHelpMessage: '新增群员,群员被踢,群员退群等通知',
+ component: 'Switch'
+ },
+ {
+ component: 'Divider',
+ label: '其他通知'
+ },
+ {
+ field: 'whole.flashPhoto',
+ label: '闪照',
+ helpMessage: '目前QQ群聊闪照功能已被移除',
+ bottomHelpMessage: '开启后将转发群聊和私聊的闪照',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.botBeenBanned',
+ label: 'Bot被禁言',
+ bottomHelpMessage: 'Bot在群聊被禁言后通知主人',
+ component: 'Switch'
+ },
+ {
+ component: 'Divider',
+ label: '其他设置'
+ },
+ {
+ field: 'whole.Strangers_love',
+ label: '陌生人点赞',
+ bottomHelpMessage: '开启后赞我功能将可以陌生人点赞,不活跃的号有可能被风控',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.state',
+ label: '默认状态',
+ bottomHelpMessage: '是否将椰奶状态作为默认状态',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.notificationsAll',
+ label: '通知全部管理',
+ bottomHelpMessage: '开启后通知将会发送给所有主人',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.deltime',
+ label: '删除缓存时间',
+ helpMessage: '删除撤回消息保存的时间',
+ bottomHelpMessage: '不建议设置太久',
+ component: 'InputNumber',
+ componentProps: {
+ placeholder: '请输入删除缓存时间'
+ }
+ },
+ {
+ component: 'Divider',
+ label: '权限设置'
+ },
+ {
+ field: 'whole.sese',
+ label: 'sese',
+ bottomHelpMessage: '开放一些功能',
+ component: 'Switch'
+ },
+ {
+ field: 'whole.sesepro',
+ label: 'sesepro',
+ bottomHelpMessage: '开放全部功能',
+ component: 'Switch'
+ },
+ {
+ component: 'Divider',
+ label: 'pixiv设置'
+ },
+ {
+ field: 'pixiv.pixivDirectConnection',
+ label: 'pixiv图片直连',
+ bottomHelpMessage: '直接使用官方图片链接发送,请确保你的网络环境可以访问pixiv',
+ component: 'Switch'
+ },
+ {
+ field: 'pixiv.allowPM',
+ label: 'pixiv私聊使用',
+ bottomHelpMessage: 'pixiv是否允许私聊使用',
+ component: 'Switch'
+ },
+ {
+ field: 'pixiv.refresh_token',
+ label: 'pixiv登录刷新令牌',
+ bottomHelpMessage: '登录后直接使用账号调用官方api,不登录也可以正常使用功能',
+ component: 'Input'
+ },
+ {
+ field: 'pixiv.pixivImageProxy',
+ label: 'pixiv图片反代',
+ bottomHelpMessage: 'pixiv图片反代服务,如可以直接访问pixiv请直接打开图片直连',
+ component: 'Input'
+ },
+ {
+ field: 'pixiv.limit',
+ label: 'pixiv次数限制',
+ bottomHelpMessage: '每名用户每日次数限制(0 则无限制)',
+ component: 'InputNumber'
+ },
+ {
+ field: 'pixiv.language',
+ label: 'pixiv返回语言',
+ bottomHelpMessage: '返回语言, 会影响标签的翻译',
+ component: 'Input'
+ },
+ {
+ component: 'Divider',
+ label: '哔咔设置'
+ },
+ {
+ field: 'bika.allowPM',
+ label: '哔咔私聊使用',
+ bottomHelpMessage: '哔咔是否允许私聊使用',
+ component: 'Switch'
+ },
+ {
+ field: 'bika.bikaDirectConnection',
+ label: '哔咔图片直连',
+ bottomHelpMessage: '直接使用官方图片链接发送,请确保你的网络环境可以访问哔咔',
+ component: 'Switch'
+ },
+ {
+ field: 'bika.limit',
+ label: '哔咔次数限制',
+ bottomHelpMessage: '每名用户每日次数限制(0 则无限制)',
+ component: 'InputNumber'
+ },
+ {
+ field: 'bika.bikaImageProxy',
+ label: '哔咔图片反代',
+ bottomHelpMessage: '哔咔图片反代服务,如可以直接访问bika请直接打开图片直连',
+ component: 'Input'
+ },
+ {
+ field: 'bika.imageQuality',
+ label: '哔咔图片质量',
+ bottomHelpMessage: '哔咔返回的图片质量',
+ component: 'Select',
+ componentProps: {
+ options: [
+ { label: '低', value: 'low' },
+ { label: '中', value: 'medium' },
+ { label: '高', value: 'high' },
+ { label: '原图', value: 'original' }
+ ],
+ placeholder: '请选择图片质量'
+ }
+ },
+ {
+ component: 'Divider',
+ label: '搜图设置'
+ },
+ {
+ field: 'picSearch.isMasterUse',
+ label: '搜图主人独享',
+ bottomHelpMessage: '搜图是否只有主人能用',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.allowPM',
+ label: '搜图私聊使用',
+ bottomHelpMessage: '搜图是否允许私聊使用',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.ascii2dUsePuppeteer',
+ label: 'Puppeteer绕cf',
+ bottomHelpMessage: '是否使用 Puppeteer 请求 ascii2d 以绕过 cf js challenge',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.hideImg',
+ label: '隐藏结果缩略图',
+ bottomHelpMessage: '隐藏所有搜索结果的缩略图',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.hideImgWhenWhatanimeR18',
+ label: 'whatanime R18 隐藏图',
+ bottomHelpMessage: 'whatanime 得到 R18 结果时隐藏结果缩略图',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.whatanimeSendVideo',
+ label: 'whatanime预览视频',
+ bottomHelpMessage: 'whatanime 发送预览视频,R18 结果不会发送',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.useAscii2dWhenLowAcc',
+ label: 'saucenao 相似度过低使用ascii2d',
+ bottomHelpMessage: '是否在 saucenao 相似度过低时自动使用 ascii2d',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.useAscii2dWhenFailed',
+ label: 'saucenao 搜索失败使用ascii2d',
+ bottomHelpMessage: '是否在 saucenao 搜索失败时自动使用 ascii2d',
+ component: 'Switch'
+ },
+ {
+ field: 'picSearch.limit',
+ label: '搜图次数限制',
+ bottomHelpMessage: '每名用户每日次数限制(0 则无限制)',
+ component: 'InputNumber'
+ },
+ {
+ field: 'picSearch.SauceNAOApiKey',
+ label: 'SauceNAO搜图apikey',
+ bottomHelpMessage: 'SauceNAO搜图apikey 请在 https://saucenao.com/user.php?page=search-api 进行获取',
+ component: 'Input'
+ },
+ {
+ field: 'picSearch.SauceNAOMinSim',
+ label: 'SauceNAO相似度警戒值',
+ bottomHelpMessage: 'SauceNAO搜图相似度低于这个百分比将被认定为相似度过低',
+ component: 'InputNumber'
+ },
+ {
+ field: 'picSearch.hideImgWhenSaucenaoNSFW',
+ label: 'SauceNAO NSFW 隐藏缩略图',
+ bottomHelpMessage: '哔咔返回的图片质量',
+ component: 'Select',
+ componentProps: {
+ options: [
+ { label: '不隐藏', value: 0 },
+ { label: '隐藏明确为 NSFW 的缩略图', value: 1 },
+ { label: '隐藏明确和可能为 NSFW 的缩略图', value: 2 },
+ { label: '只显示明确为非 NSFW 的缩略图', value: 3 }
+ ],
+ placeholder: '请选择严格程度'
+ }
+ },
+ {
+ field: 'picSearch.cfTLSVersion',
+ label: 'TLS 版本',
+ bottomHelpMessage: '绕过 Cloudflare Challenge 所使用的 TLS 版本,建议可选值:["TLSv1.1", "TLSv1.2"]',
+ component: 'Input'
+ },
+ {
+ field: 'picSearch.ascii2dResultMaxQuantity',
+ label: 'ascii2d结果数量',
+ bottomHelpMessage: 'ascii2d搜图返回结果的最大数量',
+ component: 'InputNumber'
+ }
+
+ ],
+ // 获取配置数据方法(用于前端填充显示数据)
+ getConfigData () {
+ return {
+ whole: Config.whole,
+ pixiv: Config.pixiv,
+ bika: Config.bika,
+ picSearch: Config.picSearch
+ }
+ },
+
+ // 设置配置的方法(前端点确定后调用的方法)
+ setConfigData (data, { Result }) {
+ for (let key in data) Config.modify(...key.split('.'), data[key])
+
+ return Result.ok({}, '保存成功辣ε(*´・ω・)з')
+ }
+ }
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/index.js b/Yunzai/plugins/yenai-plugin/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..385569cad2623a7c840b38e7f3a382065874c5ab
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/index.js
@@ -0,0 +1,53 @@
+import Ver from './components/Version.js'
+import chalk from 'chalk'
+import Data from './components/Data.js'
+import fs from 'fs'
+
+logger.info(chalk.rgb(253, 235, 255)('----ヾ( ̄▽ ̄)Bye~Bye~----'))
+logger.info(chalk.rgb(134, 142, 204)(`椰奶插件${Ver.ver}初始化~`))
+logger.info(chalk.rgb(253, 235, 255)('-------------------------'))
+
+if (!global.segment) {
+ try {
+ global.segment = (await import('oicq')).segment
+ } catch (err) {
+ global.segment = (await import('icqq')).segment
+ }
+}
+
+// 加载监听事件
+const eventsPath = './plugins/yenai-plugin/apps/events'
+const events = fs.readdirSync(eventsPath)
+ .filter(file => file.endsWith('.js'))
+for (const File of events) {
+ try {
+ logger.debug(`[Yenai-Plugin] 加载监听事件:${File}`)
+ await import(`./apps/events/${File}`)
+ } catch (e) {
+ logger.error(`[Yenai-Plugin] 监听事件错误:${File}`)
+ logger.error(e)
+ }
+}
+
+const appsPath = './plugins/yenai-plugin/apps'
+const jsFiles = Data.readDirRecursive(appsPath, 'js', 'events')
+
+let ret = jsFiles.map(file => {
+ return import(`./apps/${file}`)
+})
+
+ret = await Promise.allSettled(ret)
+
+let apps = {}
+for (let i in jsFiles) {
+ let name = jsFiles[i].replace('.js', '')
+
+ if (ret[i].status != 'fulfilled') {
+ logger.error(`载入插件错误:${logger.red(name)}`)
+ logger.error(ret[i].reason)
+ continue
+ }
+ apps[name] = ret[i].value[Object.keys(ret[i].value)[0]]
+}
+
+export { apps }
diff --git a/Yunzai/plugins/yenai-plugin/lib/common/common.js b/Yunzai/plugins/yenai-plugin/lib/common/common.js
new file mode 100644
index 0000000000000000000000000000000000000000..27fbada1f3e486fe73f567dee0e46724a59e8f66
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/common/common.js
@@ -0,0 +1,491 @@
+import child_process from 'child_process'
+import common from '../../../../lib/common/common.js'
+import Config from '../../components/Config.js'
+import setu from '../../model/setu.js'
+import moment from 'moment'
+import _ from 'lodash'
+
+// 涩涩未开启文案
+const SWITCH_ERROR = '主人没有开放这个功能哦(*/ω\*)'
+
+export default new class {
+ /**
+ * @description: 延时函数
+ * @param {*} ms 时间(毫秒)
+ */
+ sleep (ms) {
+ return new Promise((resolve) => setTimeout(resolve, ms))
+ }
+
+ /**
+ * 判断用户权限
+ * @param {*} e - 接收到的事件对象
+ * @param {'master'|'admin'|'owner'|'all'} [permission='all'] - 命令所需的权限
+ * @param {'admin'|'owner'|'all'} [role='all'] - 用户的权限
+ * @return {boolean} - 是否具有权限
+ */
+ checkPermission (e, permission = 'all', role = 'all') {
+ if (role == 'owner' && !e.group.is_owner) {
+ e.reply('我连群主都木有,这种事怎么可能做到的辣!!!', true)
+ return false
+ } else if (role == 'admin' && !e.group.is_admin && !e.group.is_owner) {
+ e.reply('我连管理员都木有,这种事怎么可能做到的辣!!!', true)
+ return false
+ }
+ // 判断权限
+ if (e.isMaster) return true
+ if (permission == 'master' && !e.isMaster) {
+ e.reply('❎ 该命令仅限主人可用', true)
+ return false
+ } else if (permission == 'owner' && !e.member.is_owner) {
+ e.reply('❎ 该命令仅限群主可用', true)
+ return false
+ } else if (permission == 'admin' && !e.member.is_admin && !e.member.is_owner) {
+ e.reply('❎ 该命令仅限管理可用')
+ return false
+ }
+ return true
+ }
+
+ /**
+ * @description: 判断涩涩权限
+ * @param {object} e oicq事件对象
+ * @param {'sesse'|'sesepro'} type 权限类型
+ * @return {boolean}
+ */
+ checkSeSePermission (e, type = 'sese') {
+ if (e.isMaster) return true
+ const { sese, sesepro } = Config.getGroup(e.group_id)
+ if (type == 'sese' && !sese && !sesepro) {
+ e.reply(SWITCH_ERROR)
+ return false
+ }
+ if (type == 'sesepro' && !sesepro) {
+ e.reply(SWITCH_ERROR)
+ return false
+ }
+ return true
+ }
+
+ /** 给主人发消息 */
+ async sendMasterMsg (msg) {
+ if (Config.whole.notificationsAll) {
+ // 发送全部管理
+ for (let index of Config.masterQQ) {
+ await common.relpyPrivate(index, msg)
+ await this.sleep(5000)
+ }
+ } else {
+ // 发给第一个管理
+ await common.relpyPrivate(Config.masterQQ[0], msg)
+ }
+ }
+
+ /**
+ * 格式化时间
+ * @param {number} time - 时间戳,以秒为单位
+ * @param {string|function} format - 时间格式,'default'为默认格式,'dd'表示天数,'hh'表示小时数,'mm'表示分钟数,'ss'表示秒数,也可以传入自定义函数
+ * @param {boolean} [repair=true] - 是否在小时数、分钟数、秒数小于10时补0
+ * @returns {(string|object)} 根据format参数返回相应的时间格式字符串或者时间对象{day, hour, minute, second}
+ */
+ formatTime (time, format, repair = true) {
+ const second = parseInt(time % 60)
+ const minute = parseInt((time / 60) % 60)
+ const hour = parseInt((time / (60 * 60)) % 24)
+ const day = parseInt(time / (24 * 60 * 60))
+ const timeObj = {
+ day,
+ hour: repair && hour < 10 ? `0${hour}` : hour,
+ minute: repair && minute < 10 ? `0${minute}` : minute,
+ second: repair && second < 10 ? `0${second}` : second
+ }
+ if (format == 'default') {
+ let result = ''
+
+ if (day > 0) {
+ result += `${day}天`
+ }
+ if (hour > 0) {
+ result += `${timeObj.hour}小时`
+ }
+ if (minute > 0) {
+ result += `${timeObj.minute}分`
+ }
+ if (second > 0) {
+ result += `${timeObj.second}秒`
+ }
+ return result
+ }
+
+ if (typeof format === 'string') {
+ format = format
+ .replace(/dd/g, day)
+ .replace(/hh/g, timeObj.hour)
+ .replace(/mm/g, timeObj.minute)
+ .replace(/ss/g, timeObj.second)
+
+ return format
+ }
+
+ if (typeof format === 'function') {
+ return format(timeObj)
+ }
+
+ return timeObj
+ }
+
+ /**
+ * 发送转发消息
+ * @async
+ * @param {object} e - 发送消息的目标对象
+ * @param {array} message - 发送的消息数组,数组每一项为转发消息的一条消息
+ * @param {object} [options] - 发送消息的配置项
+ * @param {number} [options.recallMsg=0] - 撤回时间,单位秒,默认为0表示不撤回
+ * @param {object} [options.info] - 转发发送人信息
+ * @param {string} [options.info.nickname] - 转发人昵称
+ * @param {number} [options.info.user_id] - 转发人QQ
+ * @param {string|array} [options.fkmsg] - 风控消息,不传则默认消息
+ * @param {Boolean} [options.isxml] - 处理卡片
+ * @param {Boolean} [options.xmlTitle] - XML 标题
+ * @param {Boolean} [options.oneMsg] - 用于只有一条消息,不用再转成二维数组
+ * @param {Boolean|import('icqq').Anonymous} [options.anony] - 匿名消息,若为true则发送匿名消息
+ * @param {Boolean} [options.shouldSendMsg=true] - 是否直接发送消息,true为直接发送,否则返回需要发送的消息
+ * @returns {Promise} 消息发送结果的Promise对象
+ */
+ async getforwardMsg (e, message, {
+ recallMsg = 0,
+ info,
+ fkmsg,
+ isxml,
+ xmlTitle,
+ oneMsg,
+ anony,
+ shouldSendMsg = true
+ } = {}) {
+ let forwardMsg = []
+ if (_.isEmpty(message)) throw Error('[Yenai-Plugin][sendforwardMsg][Error]发送的转发消息不能为空')
+ let add = (msg) => forwardMsg.push(
+ {
+ message: msg,
+ nickname: info?.nickname ?? (e.bot ?? Bot).nickname,
+ user_id: info?.user_id ?? (e.bot ?? Bot).uin
+ }
+ )
+ oneMsg ? add(message) : message.forEach(item => add(item))
+ // 发送
+ if (e.isGroup) {
+ forwardMsg = await e.group.makeForwardMsg(forwardMsg)
+ } else {
+ forwardMsg = await e.friend.makeForwardMsg(forwardMsg)
+ }
+
+ if (isxml && typeof (forwardMsg.data) !== 'object') {
+ // 处理转发卡片
+ forwardMsg.data = forwardMsg.data.replace('', '')
+ }
+
+ if (xmlTitle) {
+ if (typeof (forwardMsg.data) === 'object') {
+ let detail = forwardMsg.data?.meta?.detail
+ if (detail) {
+ detail.news = [{ text: xmlTitle }]
+ }
+ } else {
+ forwardMsg.data = forwardMsg.data
+ .replace(/\n/g, '')
+ .replace(/(.+?)<\/title>/g, '___')
+ .replace(/___+/, `${xmlTitle}`)
+ }
+ }
+ if (shouldSendMsg) {
+ let msgRes = await this.reply(e, forwardMsg, false, {
+ anony,
+ fkmsg,
+ recallMsg
+ })
+ return msgRes
+ } else {
+ return forwardMsg
+ }
+ }
+
+ /**
+ * 发送消息
+ *
+ * @async
+ * @param {*} e oicq 事件对象
+ * @param {Array|String} msg 消息内容
+ * @param {Boolean} quote 是否引用回复
+ * @param {Object} data 其他参数
+ * @param {Number} data.recallMsg 撤回时间
+ * @param {Boolean} data.fkmsg 风控消息
+ * @param {Boolean | import('icqq').Anonymous} data.anony 匿名消息
+ * @param {Boolean | Number} data.at 是否艾特该成员
+ * @returns {Promise} 返回发送消息后的结果对象
+ */
+ async reply (e, msg, quote, {
+ recallMsg = 0,
+ fkmsg = '',
+ at = false,
+ anony
+ } = {}) {
+ if (at && e.isGroup) {
+ let text = ''
+ if (e?.sender?.card) {
+ text = _.truncate(e.sender.card, { length: 10 })
+ }
+ if (at === true) {
+ at = Number(e.user_id)
+ } else if (!isNaN(at)) {
+ let info = e.group.pickMember(at).info
+ text = info?.card ?? info?.nickname
+ text = _.truncate(text, { length: 10 })
+ }
+
+ if (Array.isArray(msg)) {
+ msg = [segment.at(at, text), ...msg]
+ } else {
+ msg = [segment.at(at, text), msg]
+ }
+ }
+
+ let msgRes = null
+ // 发送消息
+ if (e.isGroup) {
+ // 判断是否开启匿名
+ if (anony) {
+ let getAnonyInfo = await e.group.getAnonyInfo()
+ if (!getAnonyInfo.enable) {
+ e.reply('[警告]该群未开启匿名,请启用匿名再使用匿名功能')
+ anony = false
+ }
+ }
+ msgRes = await e.group.sendMsg(msg, quote ? e : undefined, anony)
+ } else {
+ msgRes = await e.reply(msg, quote)
+ if (!msgRes) await e.reply(fkmsg || '消息发送失败,可能被风控')
+ }
+ if (recallMsg > 0 && msgRes?.message_id) {
+ if (e.isGroup) {
+ setTimeout(() => e.group.recallMsg(msgRes.message_id), recallMsg * 1000)
+ } else if (e.friend) {
+ setTimeout(() => e.friend.recallMsg(msgRes.message_id), recallMsg * 1000)
+ }
+ }
+ return msgRes
+ }
+
+ /**
+ * @description: 获取配置的撤回事件和匿名发送普通消息
+ * @param {*} e oicq
+ * @param {Array|String} msg 消息
+ * @param {Boolean} quote 是否引用回复
+ * @param {Object} data 其他参数
+ * @param {Number} data.recallMsg 撤回时间
+ * @param {Boolean} data.fkmsg 风控消息
+ * @param {Boolean | import('icqq').Anonymous} data.anony 匿名消息
+ * @return {Promise}
+ */
+ async recallsendMsg (e, msg, quote, data = {}) {
+ let recallMsg = setu.getRecallTime(e.group_id)
+ let anony = Config.getGroup(e.group_id).anonymous
+ let msgRes = this.reply(e, msg, quote, {
+ recallMsg,
+ anony,
+ ...data
+ })
+ return msgRes
+ }
+
+ /**
+ * 转发消息并根据权限撤回
+ * @async
+ * @param {Object} e - 反馈的对象
+ * @param {string|Object} msg - 要发送的消息字符串或对象
+ * @param {Object} [data={}] - 附加的数据对象
+ * @param {number} [data.recallMsg] - 消息撤回时间
+ * @param {Object} [data.info] - 附加消息信息
+ * @param {string} [data.info.nickname] - 用户昵称
+ * @param {number} [data.info.user_id] - 用户ID
+ * @param {boolean} [data.isxml=true] - 是否特殊处理转发消息
+ * @param {string} [data.xmlTitle] - XML 标题
+ * @param {Object} [data.anony] - 附加的匿名数据对象
+ * @returns {Promise} - Promise 对象,返回函数 `getforwardMsg()` 的返回值
+ */
+ async recallSendForwardMsg (e, msg, data = {}) {
+ let recalltime = setu.getRecallTime(e.group_id)
+ let anony = Config.whole.anonymous
+ return await this.getforwardMsg(e, msg, {
+ recallMsg: recalltime,
+ info: {
+ nickname: '🐔🏀',
+ user_id: 2854196306
+ },
+ isxml: true,
+ xmlTitle: e.logFnc + e.msg,
+ anony,
+ ...data
+ })
+ }
+
+ /**
+ * @description: 设置每日次数限制
+ * @param {Number} userId QQ
+ * @param {String} key
+ * @param {Number} maxlimit 最大限制
+ * @return {Prmoise}
+ */
+ async limit (userId, key, maxlimit) {
+ if (maxlimit <= 0) return true
+ let redisKey = `yenai:${key}:limit:${userId}`
+ let nowNum = await redis.get(redisKey)
+ if (nowNum > maxlimit) return false
+ if (!nowNum) {
+ await redis.set(redisKey, 1, { EX: moment().add(1, 'days').startOf('day').diff(undefined, 'second') })
+ } else {
+ await redis.incr(redisKey)
+ }
+ return true
+ }
+
+ /**
+ * @description: 取cookie
+ * @param {string} data 如:qun.qq.com
+ * @param {object} [bot] Bot对象适配e.bot
+ * @param {boolean} [transformation] 转换为Puppeteer浏览器使用的ck
+ * @return {object}
+ */
+ getck (data, bot = Bot, transformation) {
+ let cookie = bot.cookies[data]
+ let ck = cookie.replace(/=/g, '":"').replace(/;/g, '","').replace(/ /g, '').trim()
+ ck = ck.substring(0, ck.length - 2)
+ ck = JSON.parse('{"'.concat(ck).concat('}'))
+ if (transformation) {
+ let arr = []
+ for (let i in ck) {
+ arr.push({
+ name: i,
+ value: ck[i],
+ domain: data,
+ path: '/',
+ expires: Date.now() + 3600 * 1000
+ })
+ }
+ return arr
+ } else return ck
+ }
+
+ /**
+ * @description: 使用JS将数字从汉字形式转化为阿拉伯形式
+ * @param {string} s_123
+ * @return {number}
+ */
+ translateChinaNum (s_123) {
+ if (!s_123 && s_123 != 0) return s_123
+ // 如果是纯数字直接返回
+ if (/^\d+$/.test(s_123)) return Number(s_123)
+ // 字典
+ let map = new Map()
+ map.set('一', 1)
+ map.set('壹', 1) // 特殊
+ map.set('二', 2)
+ map.set('两', 2) // 特殊
+ map.set('三', 3)
+ map.set('四', 4)
+ map.set('五', 5)
+ map.set('六', 6)
+ map.set('七', 7)
+ map.set('八', 8)
+ map.set('九', 9)
+ // 按照亿、万为分割将字符串划分为三部分
+ let split = ''
+ split = s_123.split('亿')
+ let s_1_23 = split.length > 1 ? split : ['', s_123]
+ let s_23 = s_1_23[1]
+ let s_1 = s_1_23[0]
+ split = s_23.split('万')
+ let s_2_3 = split.length > 1 ? split : ['', s_23]
+ let s_2 = s_2_3[0]
+ let s_3 = s_2_3[1]
+ let arr = [s_1, s_2, s_3]
+
+ // -------------------------------------------------- 对各个部分处理 --------------------------------------------------
+ arr = arr.map(item => {
+ let result = ''
+ result = item.replace('零', '')
+ // [ '一百三十二', '四千五百', '三千二百一十三' ] ==>
+ let reg = new RegExp(`[${Array.from(map.keys()).join('')}]`, 'g')
+ result = result.replace(reg, substring => {
+ return map.get(substring)
+ })
+ // [ '1百3十2', '4千5百', '3千2百1十3' ] ==> ['0132', '4500', '3213']
+ let temp
+ temp = /\d(?=千)/.exec(result)
+ let num1 = temp ? temp[0] : '0'
+ temp = /\d(?=百)/.exec(result)
+ let num2 = temp ? temp[0] : '0'
+ temp = /\d?(?=十)/.exec(result)
+ let num3
+ if (temp === null) { // 说明没十:一百零二
+ num3 = '0'
+ } else if (temp[0] === '') { // 说明十被简写了:十一
+ num3 = '1'
+ } else { // 正常情况:一百一十一
+ num3 = temp[0]
+ }
+ temp = /\d$/.exec(result)
+ let num4 = temp ? temp[0] : '0'
+ return num1 + num2 + num3 + num4
+ })
+ // 借助parseInt自动去零
+ return parseInt(arr.join(''))
+ }
+
+ /**
+ * @description: Promise执行exec
+ * @param {String} cmd
+ * @return {*}
+ */
+ async execSync (cmd) {
+ return new Promise((resolve, reject) => {
+ child_process.exec(cmd, (error, stdout, stderr) => {
+ resolve({ error, stdout, stderr })
+ })
+ })
+ }
+
+ /**
+ * 判断一个对象或数组中的所有值是否为空。
+ *
+ * @param {Object|Array} data - 需要检查的对象或数组。
+ * @param {Array} omits - 需要忽略的属性列表。默认为空数组,表示不忽略任何属性。
+ * @returns {boolean} - 如果对象或数组中的所有值都是空值,则返回 true;否则返回 false。
+ */
+ checkIfEmpty (data, omits) {
+ const filteredData = _.omit(data, omits)
+ return _.every(filteredData, (value) =>
+ _.isPlainObject(value) ? this.checkIfEmpty(value) : _.isEmpty(value))
+ }
+
+ /**
+ * 处理异常并返回错误消息。
+ *
+ * @param {object} e - 事件对象。
+ * @param {Error} ErrorObj - 要检查的错误对象。
+ * @param {Object} options - 可选参数。
+ * @param {string} options.MsgTemplate - 错误消息的模板。
+ * @return {Porimse|false} 如果 ErrorObj 不是 Error 的实例,则返回 false;否则返回oicq消息返回值。
+ */
+ handleException (e, ErrorObj, { MsgTemplate } = {}) {
+ if (!(ErrorObj instanceof Error)) return false
+ let ErrMsg = ''
+ if (ErrorObj.name == 'Error') {
+ ErrMsg = ErrorObj.message
+ } else {
+ ErrMsg = ErrorObj.stack
+ logger.error(ErrorObj)
+ }
+ ErrMsg = MsgTemplate ? MsgTemplate.replace('{error}', ErrMsg) : ErrMsg
+ return e.reply(ErrMsg)
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/lib/puppeteer/devices.js b/Yunzai/plugins/yenai-plugin/lib/puppeteer/devices.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2b77fcd5615f38386cfae987b60c6640fda075d
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/puppeteer/devices.js
@@ -0,0 +1,19 @@
+// 适配低版本puppeteer
+const _puppeteer = await import('puppeteer')
+
+export default {
+ QQTheme: {
+ name: 'QQTheme',
+ userAgent:
+ 'Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/98.0.4758.102 MQQBrowser/6.2 TBS/046317 Mobile Safari/537.36 V1_AND_SQ_8.9.10_3296_YYB_D A_8091000 QQ/8.9.10.9145 NetType/WIFI WebP/0.3.0 Pixel/1080 StatusBarHeight/80 SimpleUISwitch/0 QQTheme/1000 InMagicWin/0 StudyMode/0 CurrentMode/0 CurrentFontScale/1.0 GlobalDensityScale/0.98181814 AppId/537135947',
+ viewport: {
+ width: 375,
+ height: 667,
+ deviceScaleFactor: 2,
+ isMobile: true,
+ hasTouch: true,
+ isLandscape: false
+ }
+ },
+ ..._puppeteer.devices
+}
diff --git a/Yunzai/plugins/yenai-plugin/lib/puppeteer/puppeteer.js b/Yunzai/plugins/yenai-plugin/lib/puppeteer/puppeteer.js
new file mode 100644
index 0000000000000000000000000000000000000000..04d4f807eb14b9efb7780cd618a1d8425ebeb021
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/puppeteer/puppeteer.js
@@ -0,0 +1,206 @@
+import _ from 'lodash'
+import devices from './devices.js'
+import render from './render.js'
+import puppeteer from 'puppeteer'
+// let puppeteer = null
+// let StealthPlugin = null
+// try {
+// puppeteer = (await import('puppeteer-extra')).default
+// StealthPlugin = (await import('puppeteer-extra-plugin-stealth')).default
+// puppeteer.use(StealthPlugin())
+// } catch {}
+
+class NewPuppeteer {
+ constructor () {
+ this.browser = false
+ this.config = {
+ args: ['--no-sandbox'],
+ headless: 'new'
+ }
+ this.lock = false
+ this.shoting = []
+ /** 截图数达到时重启浏览器 避免生成速度越来越慢 */
+ this.restartNum = 100
+ /** 截图次数 */
+ this.renderNum = 0
+ }
+
+ /**
+ * 截取网页截图
+ *
+ * @async
+ * @param {Object} options - 参数选项对象
+ * @param {string} options.url - 网页URL地址
+ * @param {Object|false} [options.headers=false] - 请求头信息
+ * @param {Object|false} [options.setViewport=false] - 设置浏览器视窗大小
+ * @param {boolean} [options.font=false] - 是否设置字体样式
+ * @param {Object|false} [options.cookie=false] - 设置cookie信息
+ * @param {boolean} [options.fullPage=true] - 是否截取整个网页
+ * @param {string|boolean} [options.emulate=false] - 模拟设备信息
+ * @param {Array|false} [options.click=false] - 点击事件
+ * @returns {Promise} Promise对象,如果截图成功返回构造图片消息,否则返回false
+ */
+ async Webpage ({
+ url,
+ headers = false,
+ setViewport = false,
+ font = false,
+ cookie = false,
+ fullPage = true,
+ emulate = false,
+ click = false
+ }) {
+ if (!(await this.launch())) {
+ return false
+ }
+ let buff = ''
+ let start = Date.now()
+ let name = _.truncate(url)
+ this.shoting.push(name)
+ try {
+ const page = await this.browser.newPage()
+ // 设置请求头
+ if (headers) await page.setExtraHTTPHeaders(headers)
+ // 设置cookie
+ if (cookie) await page.setCookie(...cookie)
+ // 模拟设备
+ if (emulate) await page.emulate(devices[emulate] || emulate)
+ // 设置宽度
+ if (setViewport) await page.setViewport(setViewport)
+ // 打卡新标签页
+ await page.goto(url, { timeout: 1000 * 60, waitUntil: 'networkidle0' })
+ // 设置字体
+ if (font) {
+ await page.addStyleTag({
+ content:
+ '* {font-family: "汉仪文黑-65W","雅痞-简","圆体-简","PingFang SC","微软雅黑", sans-serif !important;}'
+ })
+ }
+ // 点击事件
+ if (click) {
+ for (let i of click) {
+ await page.click(i.selector)
+ await page.waitForTimeout(i.time)
+ }
+ }
+
+ buff = await page.screenshot({
+ // path: './paper.jpeg',
+ type: 'jpeg',
+ fullPage,
+ quality: 100
+ })
+ await page.close().catch((err) => logger.error(err))
+ } catch (err) {
+ logger.error(`网页截图失败:${name}${err}`)
+ /** 关闭浏览器 */
+ if (this.browser) {
+ await this.browser.close().catch((err) => logger.error(err))
+ }
+ this.browser = false
+ buff = ''
+ return false
+ }
+ this.shoting.pop()
+
+ if (!buff) {
+ logger.error(`网页截图为空:${name}`)
+ return false
+ }
+
+ this.renderNum++
+
+ /** 计算图片大小 */
+ let kb = (buff.length / 1024).toFixed(2) + 'kb'
+
+ logger.mark(
+ `[网页截图][${name}][${this.renderNum}次] ${kb} ${logger.green(
+ `${Date.now() - start}ms`
+ )}`
+ )
+
+ this.restart()
+ return segment.image(buff)
+ }
+
+ async launch () {
+ if (this.browser) return this.browser
+ logger.mark('[Yenai-Plugin]Puppeteer launching')
+ // if (!puppeteer) {
+ // logger.error(`[Yenai-Plugin][Puppeteer]缺少依赖项,请执行 ${logger.red('pnpm add puppeteer-extra puppeteer-extra-plugin-stealth -w')}`)
+ // return false
+ // }
+ this.browser = await puppeteer.launch(this.config).catch((err) => {
+ logger.error(err.toString())
+ if (String(err).includes('correct Chromium')) {
+ logger.error(
+ '没有正确安装Chromium,可以尝试执行安装命令:node ./node_modules/puppeteer/install.js'
+ )
+ }
+ })
+ if (!this.browser) {
+ logger.error('[Yenai-Plugin]puppeteer launching error')
+ return false
+ }
+ logger.mark('[Yenai-Plugin]Puppeteer launched')
+ /** 监听Chromium实例是否断开 */
+ this.browser.on('disconnected', (e) => {
+ logger.error('[Yenai-Plugin]Chromium实例关闭或崩溃!')
+ this.browser = false
+ })
+
+ return this.browser
+ }
+
+ /**
+ * 异步跳转到指定 URL,等待指定选择器,返回页面数据对象。
+ * @async
+ * @param {string} url - 要跳转的 URL。
+ * @param {string} waitSelector - 等待页面渲染的选择器。
+ * @returns {Object} - 包含 URL 和页面数据的对象。
+ * @throws 如果导航或页面数据检索失败,将抛出错误。
+ */
+ async get (url, waitSelector) {
+ if (!(await this.launch())) {
+ return false
+ }
+ const page = await this.browser.newPage()
+ try {
+ logger.debug('Puppeteer get', url)
+ await page.goto(url)
+ await page.waitForSelector(waitSelector).catch((e) => {
+ logger.error(`Puppeteer get "${url}" wait "${waitSelector}" error`)
+ logger.error(e)
+ })
+ const res = await page.evaluate(() => ({
+ url: window.location.href,
+ data: document.documentElement.outerHTML
+ }))
+ return res
+ } catch (e) {
+ logger.error(`Puppeteer get "${url}" error`)
+ throw e
+ } finally {
+ page.close()
+ }
+ }
+
+ /** 重启 */
+ restart () {
+ /** 截图超过重启数时,自动关闭重启浏览器,避免生成速度越来越慢 */
+ if (this.renderNum % this.restartNum === 0) {
+ if (this.shoting.length <= 0) {
+ setTimeout(async () => {
+ if (this.browser) {
+ await this.browser.close().catch((err) => logger.error(err))
+ }
+ this.browser = false
+ logger.mark('[Yenai-Plugin]puppeteer 关闭重启...')
+ }, 100)
+ }
+ }
+ }
+}
+Object.setPrototypeOf(NewPuppeteer.prototype, render)
+
+export default new NewPuppeteer()
diff --git a/Yunzai/plugins/yenai-plugin/lib/puppeteer/render.js b/Yunzai/plugins/yenai-plugin/lib/puppeteer/render.js
new file mode 100644
index 0000000000000000000000000000000000000000..68bd31b25755670fd7d443b0a4e12c0bcd2873a4
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/puppeteer/render.js
@@ -0,0 +1,66 @@
+import fs from 'fs'
+import { Config, Data, Plugin_Name, Version } from '../../components/index.js'
+import puppeteer from '../../../../lib/puppeteer/puppeteer.js'
+const _path = process.cwd()
+
+export default new class {
+/**
+ * @description: 渲染HTML
+ * @param {String} path 文件路径
+ * @param {Object} params 参数
+ * @param {Object} cfg
+ */
+ async render (path, params, cfg) {
+ let [app, tpl] = path.split('/')
+ let { e } = cfg
+ let layoutPath =
+ process.cwd() + `/plugins/${Plugin_Name}/resources/common/layout/`
+ let resPath = `../../../../../plugins/${Plugin_Name}/resources/`
+ Data.createDir(`data/html/${Plugin_Name}/${app}/${tpl}`, 'root')
+ let data = {
+ ...params,
+ _plugin: Plugin_Name,
+ saveId: params.saveId || params.save_id || tpl,
+ tplFile: `./plugins/${Plugin_Name}/resources/${app}/${tpl}.html`,
+ pluResPath: resPath,
+ _res_path: resPath,
+ _layout_path: layoutPath,
+ _tpl_path:
+ process.cwd() + `/plugins/${Plugin_Name}/resources/common/tpl/`,
+ defaultLayout: layoutPath + 'default.html',
+ elemLayout: layoutPath + 'elem.html',
+ pageGotoParams: {
+ waitUntil: 'networkidle0'
+ },
+ sys: {
+ scale: this.scale(cfg.scale || 1),
+ copyright: `Created By ${Version.name}${Version.yunzai} & Yenai-Plugin${Version.ver}`
+ },
+ quality: 100
+ }
+ if (process.argv.includes('web-debug')) {
+ // debug下保存当前页面的渲染数据,方便模板编写与调试
+ // 由于只用于调试,开发者只关注自己当时开发的文件即可,暂不考虑app及plugin的命名冲突
+ let saveDir = _path + '/data/ViewData/'
+ if (!fs.existsSync(saveDir)) {
+ fs.mkdirSync(saveDir)
+ }
+ let file = saveDir + tpl + '.json'
+ data._app = app
+ fs.writeFileSync(file, JSON.stringify(data))
+ }
+ let base64 = await puppeteer.screenshot(`${Plugin_Name}/${app}/${tpl}`, data)
+ let ret = true
+ if (base64) {
+ ret = await e.reply(base64)
+ }
+ return cfg.retMsgId ? ret : true
+ }
+
+ scale (pct = 1) {
+ let scale = Config.whole.renderScale
+ scale = Math.min(2, Math.max(0.5, scale / 100))
+ pct = pct * scale
+ return `style='transform:scale(${pct})'`
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/lib/request/httpsProxyAgentMod.js b/Yunzai/plugins/yenai-plugin/lib/request/httpsProxyAgentMod.js
new file mode 100644
index 0000000000000000000000000000000000000000..c57c1bc4dd555e33325a72d5a72b6e9cad1d27f5
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/request/httpsProxyAgentMod.js
@@ -0,0 +1,10 @@
+import HttpsProxyAgentOrig from 'https-proxy-agent'
+
+export class HttpsProxyAgent extends HttpsProxyAgentOrig.HttpsProxyAgent {
+ constructor (opts) {
+ super(opts)
+ this.tlsConnectionOptions = opts.tls
+ const callback = this.callback.bind(this)
+ this.callback = (req, opts) => callback(req, Object.assign(opts, this.tlsConnectionOptions))
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/lib/request/request.js b/Yunzai/plugins/yenai-plugin/lib/request/request.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0b98398b409532ff6e589c9f7044e36d11a27cf
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/lib/request/request.js
@@ -0,0 +1,215 @@
+import fetch from 'node-fetch'
+import { Config, Plugin_Path } from '../../components/index.js'
+import { Agent } from 'https'
+import { HttpsProxyAgent } from './httpsProxyAgentMod.js'
+import _ from 'lodash'
+
+const CHROME_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
+const POSTMAN_UA = 'PostmanRuntime/7.29.0'
+
+class HTTPResponseError extends Error {
+ constructor (response) {
+ super(`HTTP Error Response: ${response.status} ${response.statusText}`)
+ this.response = response
+ }
+}
+
+const checkStatus = response => {
+ if (response.ok) {
+ // response.status >= 200 && response.status < 300
+ return response
+ } else {
+ throw new HTTPResponseError(response)
+ }
+}
+
+export const qs = (obj) => {
+ let res = ''
+ for (const [k, v] of Object.entries(obj)) { res += `${k}=${encodeURIComponent(v)}&` }
+ return res.slice(0, res.length - 1)
+}
+
+export default new class {
+ /**
+ * 发送HTTP GET请求并返回响应
+ * @async
+ * @function
+ * @param {string} url - 请求的URL
+ * @param {Object} [options={}] - 请求的配置项
+ * @param {Object} [options.params] - 请求的参数
+ * @param {Object} [options.headers] - 请求的HTTP头部
+ * @param {boolean} [options.closeCheckStatus=false] - 是否关闭状态检查
+ * @param {'buffer'|'json'|'text'|'arrayBuffer'|'formData'|'blob'}[options.statusCode] - 期望的返回数据,如果设置了该值,则返回响应数据的特定的方法(如json()、text()等)
+ * @returns {Promise} - HTTP响应或响应数据
+ * @throws {Error} - 如果请求失败,则抛出错误
+ */
+ async get (url, options = {}) {
+ // 处理参数
+ if (options.params) {
+ url = url + '?' + qs(options.params)
+ }
+ logger.debug(`[Yenai-Plugin] GET请求:${decodeURI(url)}`)
+ options.headers = {
+ 'User-Agent': CHROME_UA,
+ ...options.headers
+ }
+ if (!options.agent) options.agent = this.getAgent()
+ try {
+ let res = await fetch(url, options)
+ if (!options.closeCheckStatus) {
+ res = checkStatus(res)
+ }
+ if (options.statusCode) {
+ return res[options.statusCode]()
+ }
+ return res
+ } catch (err) {
+ logger.error(err)
+ throw Error(
+ `Request Get Error,${err.message.match(/reason:(.*)/i) || err.message}`
+ )
+ }
+ }
+
+ /**
+ * 发送HTTP POST请求并返回响应
+ * @async
+ * @function
+ * @param {string} url - 请求的URL
+ * @param {object} [options={}] - 请求的配置项
+ * @param {object} [options.params] - 请求的参数
+ * @param {object} [options.headers] - 请求的HTTP头部
+ * @param {object} [options.data] - 请求的数据
+ * @param {boolean} [options.closeCheckStatus=false] - 是否关闭状态检查
+ * @param {'buffer'|'json'|'text'|'arrayBuffer'|'formData'|'blob'} [options.statusCode] - 期望的返回数据,如果设置了该值,则返回响应数据的特定的方法(如json()、text()等)
+ * @returns {Promise} - HTTP响应或响应数据
+ * @throws {Error} - 如果请求失败,则抛出错误
+ */
+ async post (url, options = {}) {
+ options.method = 'POST'
+ options.headers = {
+ 'User-Agent': CHROME_UA,
+ 'Content-Type': 'application/json',
+ ...options.headers
+ }
+ if (options.params) {
+ url = url + '?' + qs(options.params)
+ }
+ logger.debug(`[Yenai-Plugin] POST请求:${decodeURI(url)}`)
+ if (options.data) {
+ if (/json/.test(options.headers['Content-Type'])) {
+ options.body = JSON.stringify(options.data)
+ } else if (
+ /x-www-form-urlencoded/.test(options.headers['Content-Type'])
+ ) {
+ options.body = qs(options.data)
+ } else {
+ options.body = options.data
+ }
+ delete options.data
+ }
+ if (!options.agent) options.agent = this.getAgent()
+ try {
+ let res = await fetch(url, options)
+ if (!options.closeCheckStatus) {
+ res = checkStatus(res)
+ }
+ if (options.statusCode) {
+ return res[options.statusCode]()
+ }
+ return res
+ } catch (err) {
+ logger.error(err)
+ throw Error(
+ `Request Post Error,reason:${err.message.match(/reason:(.*)/)[1]}`
+ )
+ }
+ }
+
+ /**
+ * @description: 绕cf Get请求
+ * @param {String} url
+ * @param {Object} options 同fetch第二参数
+ * @param {Object} options.params 请求参数
+ * @return {FetchObject}
+ */
+ async cfGet (url, options = {}) {
+ options.agent = this.getAgent(true)
+ options.headers = {
+ 'User-Agent': POSTMAN_UA,
+ ...options.headers
+ }
+ return this.get(url, options)
+ }
+
+ /**
+ * @description: 绕cf Post请求
+ * @param {String} url
+ * @param {Object} options 同fetch第二参数
+ * @param {Object|String} options.data 请求参数
+ * @return {FetchObject}
+ */
+ async cfPost (url, options = {}) {
+ options.agent = this.getAgent(true)
+ options.headers = {
+ 'User-Agent': POSTMAN_UA,
+ ...options.headers
+ }
+ return this.post(url, options)
+ }
+
+ getAgent (cf) {
+ let { proxyAddress, switchProxy } = Config.proxy
+ let { cfTLSVersion } = Config.picSearch
+ return cf
+ ? this.getTlsVersionAgent(proxyAddress, cfTLSVersion)
+ : switchProxy
+ ? new HttpsProxyAgent(proxyAddress)
+ : false
+ }
+
+ /**
+ * 从代理字符串获取指定 TLS 版本的代理
+ * @param {string} str
+ * @param {import('tls').SecureVersion} tlsVersion
+ */
+ getTlsVersionAgent (str, tlsVersion) {
+ const tlsOpts = {
+ maxVersion: tlsVersion,
+ minVersion: tlsVersion
+ }
+ if (typeof str === 'string') {
+ const isHttp = str.startsWith('http')
+ if (isHttp && Config.proxy.switchProxy) {
+ const opts = {
+ ..._.pick(new URL(str), [
+ 'protocol',
+ 'hostname',
+ 'port',
+ 'username',
+ 'password'
+ ]),
+ tls: tlsOpts
+ }
+ return new HttpsProxyAgent(opts)
+ }
+ }
+ return new Agent(tlsOpts)
+ }
+
+ /**
+ * @description: 代理请求图片
+ * @param {String} url 图片链接
+ * @param {Boolean} cache 是否缓存
+ * @param {Number} timeout 超时时间
+ * @param {Object} headers 请求头
+ * @return {Porimes} 构造图片消息
+ */
+ async proxyRequestImg (url, { cache, timeout, headers } = {}) {
+ if (!this.getAgent()) return segment.image(url, cache, timeout, headers)
+ let Request = await this.get(url, {
+ headers
+ }).catch(err => logger.error(err))
+ return segment.image(Request?.body ?? `${Plugin_Path}/resources/img/imgerror.png`, cache, timeout)
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/model/Bika.js b/Yunzai/plugins/yenai-plugin/model/Bika.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0fcfdf126647d4dfe70cbf1b5955d2257768505
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/Bika.js
@@ -0,0 +1,206 @@
+import _ from 'lodash'
+import request from '../lib/request/request.js'
+import { Config } from '../components/index.js'
+
+export default new (class {
+ constructor () {
+ this.domain = 'https://api.obfs.dev/api/bika'
+ this.hearder = {
+ headers: {
+ 'x-image-quality': Config.bika.imageQuality
+ }
+ }
+ this.searchCaching = null
+ this.idNext = null
+ }
+
+ get imgproxy () {
+ return Config.bika.bikaDirectConnection ? undefined : `https://${Config.bika.bikaImageProxy}/`
+ }
+
+ /**
+ * 关键词搜索作品
+ * @param {string} keyword - 搜索关键词
+ * @param {number} [page=1] - 页码,默认为1
+ * @param {'dd'|'da'|'ld'|'vd'} [sort='ld'] - 排序方式:dd(最新发布)、da(最早发布)、ld(最多喜欢)、vd(最多浏览),默认为'ld'
+ * @param {string} [type='advanced'] - 搜索类型:advanced(高级)、category(类别)、author(作者),默认为'advanced'
+ * @throws {Error} 当未找到作品时,会抛出异常
+ * @returns {Array} 返回搜索结果信息数组
+ */
+ async search (keyword, page = 1, type = 'advanced', sort = 'ld') {
+ let types = [
+ {
+ alias: ['关键词', 'advanced', '高级'],
+ url: `${this.domain}/advanced_search?keyword=${keyword}&page=${page}&sort=${sort}`
+ },
+ {
+ alias: ['类别', 'category'],
+ url: `${this.domain}/category_list?category=${keyword}&page=${page}&sort=${sort}`
+ },
+ {
+ alias: ['作者', 'author'],
+ url: `${this.domain}/author_list?author=${keyword}&page=${page}&sort=${sort}`
+ }
+ ]
+ type = types.find(item => item.alias.includes(type))
+ let res = await request.get(type.url, this.hearder)
+ .then(res => res.json())
+ .catch(err => {
+ logger.error(err)
+ throw Error(`bika search Error,${err.message.match(/reason:(.*)/i) || err.message}`)
+ })
+ let { docs, total, page: pg, pages } = res.data.comics
+ if (total == 0) throw Error(`未找到作品,换个${type.alias[0]}试试吧`)
+ this.searchCaching = docs
+ let msg = [
+ `共找到${total}个关于「${keyword}」${type.alias[0]}的作品`,
+ `当前为第${pg}页,共${pages}页`
+ ]
+ for (let [index, item] of docs.entries()) {
+ let { title, tags, categories, author, description = '未知', likesCount, thumb, _id, finished } = item
+ msg.push(_id)
+ msg.push([
+ `${index + 1}、${title}\n`,
+ `作者:${author}\n`,
+ `描述:${_.truncate(description)}\n`,
+ `分类:${categories.join(',')}\n`,
+ `喜欢:${likesCount}\n`,
+ `完结:${finished}\n`,
+ tags ? `tag:${_.truncate(tags.join(','))}\n` : '',
+ await this._requestBikaImg(thumb.fileServer, thumb.path)
+ ])
+ }
+ return msg
+ }
+
+ /**
+ * 获取漫画某一话某一页的信息及图片列表
+ * @async
+ * @param {string} id - 漫画id
+ * @param {number} [page=1] - 页码,默认为1
+ * @param {number} [order=1] - 话数,默认为1
+ * @returns {Promise} - 返回一个数组,包含漫画某一话某一页的信息及图片列表
+ * @throws {Error} - 如果返回结果中包含error,则抛出异常
+ */
+ async comicPage (id, page = 1, order = 1) {
+ let res = await request.get(`${this.domain}/comic_page?id=${id}&page=${page}&order=${order}`, this.hearder)
+ .then((res) => res.json())
+ .catch(err => {
+ logger.error(err)
+ throw Error(`bika comicPage Error,${err.message.match(/reason:(.*)/i) || err.message}`)
+ })
+ if (res.error) throw Error(res.message)
+ this.idNext = {
+ id, page, order
+ }
+ let { docs, total, page: pg, pages } = res.data.pages
+ let { _id, title } = res.data.ep
+ return [
+ `id: ${_id}, ${title}`,
+ `共${total}张,当前为第${pg}页,共${pages}页,当前为第${order}话`,
+ ...await Promise.all(docs.map(async item => await this._requestBikaImg(item.media.fileServer, item.media.path)))
+ ]
+ }
+
+ async viewComicPage (num) {
+ if (!this.searchCaching) throw Error('请先搜索后再使用此命令')
+ let id = this.searchCaching[num]._id
+ if (!id) throw Error('未获取到目标作品,请使用id进行查看')
+ return this.comicPage(id)
+ }
+
+ /**
+ * 获取下一个漫画页面或漫画章节的信息及图片列表
+ * @async
+ * @param {string} [type='comicPage'] - 请求的类型,可选值为'comicPage'或'chapter',默认为'comicPage'
+ * @returns {Promise} - 返回一个数组,包含下一个漫画页面或漫画章节的信息及图片列表
+ * @throws {Error} - 如果未找到上一个id,则抛出异常
+ */
+ async next (type = 'comicPage') {
+ if (!this.idNext) throw Error('未找到上一个id')
+ let { id, page, order } = this.idNext
+ if (type == 'chapter') {
+ order++
+ page = 1
+ } else {
+ page++
+ }
+ return await this.comicPage(id, page, order).then(res => {
+ this.idNext = { id, page, order }
+ return res
+ })
+ }
+
+ /** 类别列表 */
+ async categories () {
+ let key = 'yenai:bika:categories'
+ let res = JSON.parse(await redis.get(key))
+ if (!res) {
+ res = await request.get(`${this.domain}/categories`, this.hearder)
+ .then((res) => res.json())
+ .catch(err => {
+ logger.error(err)
+ throw Error(`bika categories Error,${err.message.match(/reason:(.*)/i) || err.message}`)
+ })
+ if (res.error) throw Error(res.message)
+ res = res.data.categories.filter(item => !item.isWeb)
+ await redis.set(key, JSON.stringify(res), { EX: 43200 })
+ }
+ return await Promise.all(res.map(async item => {
+ let { title, thumb, description = '未知' } = item
+ return [
+ `category: ${title}\n`,
+ `描述:${description}\n`,
+ await this._requestBikaImg(thumb.fileServer, thumb.path)
+ ]
+ }))
+ }
+
+ /**
+ * 获取指定id的Bika漫画详细信息
+ * @async
+ * @param {string} id - 漫画的id
+ * @returns {Promise} - 返回一个由字符串组成的数组,包含漫画的详细信息和封面图片
+ */
+ async comicDetail (id) {
+ let res = await request.get(`${this.domain}/comic_detail?id=${id}`, this.hearder)
+ .then((res) => res.json())
+ .catch(err => {
+ logger.error(err)
+ throw Error(`bika comicDetail Error,${err.message.match(/reason:(.*)/i) || err.message}`)
+ })
+ if (res.error) throw Error(res.message)
+ let {
+ _id, title, description, author, chineseTeam, categories, tags, pagesCount, epsCount, finished, totalLikes, totalViews, totalComments, thumb
+ } = res.data.comic
+ return [
+ `id: ${_id}\n`,
+ `title:${title}\n`,
+ `描述:${_.truncate(description)}\n`,
+ `作者:${author}\n`,
+ `汉化:${chineseTeam}\n`,
+ `页数:${pagesCount}\n`,
+ `话数:${epsCount}\n`,
+ `完结:${finished}\n`,
+ `喜欢:${totalLikes}\n`,
+ `浏览量:${totalViews}\n`,
+ `评论量:${totalComments}\n`,
+ `分类:${categories.join(',')}\n`,
+ `tag:${tags.join(',')}`,
+ await this._requestBikaImg(thumb.fileServer, thumb.path)
+ ]
+ }
+
+ /**
+ * 请求Bika漫画网站的图片
+ * @async
+ * @param {string} fileServer - 图片所在的文件服务器
+ * @param {string} path - 图片的路径
+ * @returns {Promise} - 返回构造图片消息
+ */
+ async _requestBikaImg (fileServer, path) {
+ fileServer = /static/.test(fileServer) ? fileServer : fileServer + '/static/'
+ let url = (/picacomic.com/.test(fileServer) && this.imgproxy ? this.imgproxy : fileServer) + path
+ return request.proxyRequestImg(url)
+ }
+})()
diff --git a/Yunzai/plugins/yenai-plugin/model/GroupAdmin.js b/Yunzai/plugins/yenai-plugin/model/GroupAdmin.js
new file mode 100644
index 0000000000000000000000000000000000000000..687137c1a62413b47e06c84edc6dc413179310d7
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/GroupAdmin.js
@@ -0,0 +1,415 @@
+import _ from 'lodash'
+import moment from 'moment'
+import loader from '../../../lib/plugins/loader.js'
+import { Config } from '../components/index.js'
+import { common, QQApi } from './index.js'
+import { Time_unit, ROLE_MAP } from '../constants/other.js'
+
+// 无管理文案
+const ROLE_ERROR = '我连管理员都木有,这种事怎么可能做到的辣!!!'
+export default class {
+ constructor (e) {
+ this.e = e
+ this.Bot = e.bot ?? Bot
+ this.MuteTaskKey = 'yenai:MuteTasks'
+ }
+
+ /**
+ * 获取指定群中所有成员的信息映射表
+ * @param {number} groupId - 群号码
+ * @param {boolean} [iskey=false] - 是否只返回成员 QQ 号码列表(键)
+ * @returns {Promise} - 成员信息数组,或成员 QQ 号码数组(取决于 iskey 参数)
+ */
+ async _getMemberMap (groupId, iskey = false) {
+ let Map = await this.Bot.pickGroup(groupId - 0).getMemberMap(true)
+ return Array.from(iskey ? Map.keys() : Map.values())
+ }
+
+ /**
+ * 获取某个群组中被禁言的成员列表。
+ *
+ * @async
+ * @param {number} groupId - 群组 ID。
+ * @param {boolean} [info=false] - 是否返回成员信息。
+ * @returns {Promise|Array>>} 如果 `info` 为 `false`,返回被禁言成员对象的数组;否则,返回被禁言成员信息的数组。
+ * @throws {Error} 如果没有被禁言的成员,抛出异常。
+ */
+ async getMuteList (groupId, info = false) {
+ let list = await this._getMemberMap(groupId)
+ let mutelist = list.filter(item => {
+ let time = item.shut_up_timestamp ?? item.shutup_time
+ return time != 0 && (time - (Date.now() / 1000)) > 0
+ })
+ if (_.isEmpty(mutelist)) throw Error('没有被禁言的人哦~')
+ if (!info) return mutelist
+ return mutelist.map(item => {
+ let time = item.shut_up_timestamp ?? item.shutup_time
+ return [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\n昵称:${item.card || item.nickname}\n`,
+ `QQ:${item.user_id}\n`,
+ `群身份:${ROLE_MAP[item.role]}\n`,
+ `禁言剩余时间:${common.formatTime(time - Date.now() / 1000, 'default')}\n`,
+ `禁言到期时间:${new Date(time * 1000).toLocaleString()}`
+ ]
+ })
+ }
+
+ /**
+ * 解除指定群中所有成员的禁言状态
+ * @param {number} groupId - 群号码
+ * @returns {Promise} - 由所有解禁操作的 Promise 对象组成的数组
+ */
+ async releaseAllMute () {
+ let mutelist = await this.getMuteList(this.e.group_id)
+ for (let i of mutelist) {
+ this.e.group.muteMember(i.user_id, 0)
+ }
+ }
+
+ /**
+ * 获取指定时间段内未活跃的群成员信息
+ *
+ * @async
+ * @param {number} groupId - 群号码
+ * @param {number} times - 时间数值
+ * @param {string} unit - 时间单位
+ * @param {number} [page=1] - 需要获取的页码,默认为 1
+ * @returns {Promise>} - 由每个成员的信息组成的数组,包括成员的 QQ 号码、昵称、最后发言时间等信息
+ * @throws {Error} 如果没有符合条件的成员,将抛出一个错误
+ * @throws {Error} 如果指定的页码不存在,将抛出一个错误
+ */
+ async getNoactiveInfo (groupId, times, unit, page = 1) {
+ let list = await this.noactiveList(groupId, times, unit)
+ list.sort((a, b) => a.last_sent_time - b.last_sent_time)
+ let msg = list.map(item =>
+ [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\nQQ:${item.user_id}\n`,
+ `昵称:${item.card || item.nickname}\n`,
+ `最后发言时间:${moment(item.last_sent_time * 1000).format('YYYY-MM-DD HH:mm:ss')}`
+ ]
+ )
+ let pageChunk = _.chunk(msg, 30)
+ if (page > pageChunk.length) throw Error('哪有那么多人辣o(´^`)o')
+
+ let msgs = pageChunk[page - 1]
+ msgs.unshift(`当前为第${page}页,共${pageChunk.length}页,本页共${msgs.length}人,总共${msg.length}人`)
+ msgs.unshift(`以下为${times}${unit}没发言过的坏淫`)
+ if (page < pageChunk.length) {
+ msgs.splice(2, 0, `可用 "#查看${times}${unit}没发言过的人第${page + 1}页" 翻页`)
+ }
+ return msgs
+ }
+
+ /**
+ * @description: 清理多久没发言的人
+ * @param {Number} groupId 群号
+ * @param {Number} times 时间数
+ * @param {String} unit 单位 (天)
+ * @return {Promise}
+ * @throws {Error} 如果没有符合条件的成员,将抛出一个错误
+ */
+ async clearNoactive (groupId, times, unit) {
+ let list = await this.noactiveList(groupId, times, unit)
+ list = list.map(item => item.user_id)
+ return this.BatchKickMember(groupId, list)
+ }
+
+ /**
+ * @description: 返回多少时间没发言的人列表
+ * @param {Number} groupId 群号
+ * @param {Number} times 时间数
+ * @param {String} unit 单位 (天)
+ * @return {Promise}
+ * @throws {Error} 如果没有符合条件的成员,将抛出一个错误
+ */
+ async noactiveList (groupId, times = 1, unit = '月') {
+ let nowtime = parseInt(Date.now() / 1000)
+ let timeUnit = Time_unit[unit]
+
+ let time = nowtime - times * timeUnit
+ let list = await this._getMemberMap(groupId)
+
+ list = list.filter(item => item.last_sent_time < time && item.role == 'member' && item.user_id != this.Bot.uin)
+ if (_.isEmpty(list)) throw Error(`暂时没有${times}${unit}没发言的淫哦╮( •́ω•̀ )╭`)
+ return list
+ }
+
+ /**
+ * @description: 返回从未发言的人
+ * @param {Number} geoupId 群号
+ * @return {Promise}
+ * @throws {Error} 如果没有符合条件的成员,将抛出一个错误
+ */
+ async getNeverSpeak (groupId) {
+ let list = await this._getMemberMap(groupId)
+ list = list.filter(item =>
+ item.join_time == item.last_sent_time &&
+ item.role == 'member' &&
+ item.user_id != this.Bot.uin
+ )
+ if (_.isEmpty(list)) throw Error('本群暂无从未发言的人哦~')
+ return list
+ }
+
+ /**
+ * 获取群内从未发言的成员信息
+ *
+ * @async
+ * @param {string|number} groupId - 群号
+ * @param {number} [page=1] - 分页页码,默认为第一页
+ * @returns {Promise>} 包含从未发言成员信息的数组
+ * @throws {Error} 如果没有符合条件的成员,将抛出一个错误
+ * @throws {Error} 当页码超出范围时抛出错误
+ */
+ async getNeverSpeakInfo (groupId, page = 1) {
+ let list = await this.getNeverSpeak(groupId)
+ list.sort((a, b) => a.join_time - b.join_time)
+ let msg = list.map(item => {
+ return [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\nQQ:${item.user_id}\n`,
+ `昵称:${item.card || item.nickname}\n`,
+ `进群时间:${moment(item.join_time * 1000).format('YYYY-MM-DD HH:mm:ss')}`
+ ]
+ })
+ let pageChunk = _.chunk(msg, 30)
+ if (page > pageChunk.length) throw Error('哪有那么多人辣o(´^`)o')
+
+ let msgs = pageChunk[page - 1]
+ msgs.unshift(`当前为第${page}页,共${pageChunk.length}页,本页共${msgs.length}人,总共${msg.length}人`)
+ msgs.unshift('以下为进群后从未发言过的坏淫')
+ if (page < pageChunk.length) {
+ msgs.splice(2, 0, `可用 "#查看从未发言过的人第${page + 1}页" 翻页`)
+ }
+ return msgs
+ }
+
+ /**
+ * 批量踢出群成员
+ *
+ * @param {number} groupId - 群号码
+ * @param {Array} arr - 成员 QQ 号码数组
+ * @returns {Promise>} - 包含清理结果的数组,其中清理结果可能是成功的踢出列表,也可能是错误消息
+ */
+ async BatchKickMember (groupId, arr) {
+ let res = await new QQApi(this.e).deleteGroupMember(groupId, arr)
+ let msg = [
+ '以下为每次清理的结果'
+ ]
+ res.forEach(i => {
+ if (i.ec != 0) {
+ msg.push(`错误:${JSON.stringify(res)}`)
+ } else {
+ msg.push('成功清理如下人员\n' + i.ul.map((item, index) =>
+ `${index + 1}、${item}`
+ ).join('\n'))
+ }
+ })
+ return msg
+ }
+
+ /**
+ * 获取群不活跃排行榜
+ *
+ * @param {number} groupId - 群号码
+ * @param {number} num - 需要获取的排行榜长度
+ * @returns {Promise>} - 由每个成员的排行信息组成的数组,排行信息包括成员的排名,QQ 号码,昵称,最后发言时间等信息
+ */
+ async InactiveRanking (groupId, num) {
+ let list = await this._getMemberMap(groupId)
+ list.sort((a, b) => {
+ return a.last_sent_time - b.last_sent_time
+ })
+ let msg = list.slice(0, num)
+ msg = msg.map((item, index) => {
+ return [`第${index + 1}名:\n`,
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\nQQ:${item.user_id}\n`,
+ `昵称:${item.card || item.nickname}\n`,
+ `最后发言时间:${moment(item.last_sent_time * 1000).format('YYYY-MM-DD HH:mm:ss')}`
+ ]
+ })
+ msg.unshift(`不活跃排行榜top1 - top${num}`)
+ return msg
+ }
+
+ /**
+ * 获取最近加入群聊的成员列表
+ * @param {number} groupId 群号
+ * @param {number} num 返回的成员数量
+ * @return {Promise} 最近加入的成员信息列表
+ */
+ async getRecentlyJoined (groupId, num) {
+ let list = await this._getMemberMap(groupId)
+ list.sort((a, b) => {
+ return b.join_time - a.join_time
+ })
+ let msg = list.slice(0, num)
+ msg = msg.map((item) => {
+ return [
+ segment.image(`https://q1.qlogo.cn/g?b=qq&s=100&nk=${item.user_id}`),
+ `\nQQ:${item.user_id}\n`,
+ `昵称:${item.card || item.nickname}\n`,
+ `入群时间:${moment(item.join_time * 1000).format('YYYY-MM-DD HH:mm:ss')}\n`,
+ `最后发言时间:${moment(item.last_sent_time * 1000).format('YYYY-MM-DD HH:mm:ss')}`
+ ]
+ })
+ msg.unshift(`最近的${num}条入群记录`)
+ return msg
+ }
+
+ /**
+ * @description 设置指定群的禁言/解禁定时任务
+ * @param {string} group - 群号
+ * @param {string} cron - 定时任务执行时间的 Cron 表达式
+ * @param {boolean} type - 是否为禁言任务。如果为 true,则表示禁言任务;否则,表示解禁任务。
+ * @returns {Promise} - 返回操作结果。如果设置成功,则返回 true;否则,返回 false。
+ */
+ async setMuteTask (group, cron, type) {
+ let name = `椰奶群定时${type ? '禁言' : '解禁'}${group}`
+ if (loader.task.find(item => item.name == name)) return false
+ let redisTask = JSON.parse(await redis.get(this.MuteTaskKey)) || []
+ let task = {
+ cron,
+ name,
+ fnc: () => {
+ this.Bot.pickGroup(Number(group)).muteAll(type)
+ }
+ }
+ loader.task.push(_.cloneDeep(task))
+ loader.creatTask()
+ redisTask.push({ cron, group, type, botId: this.Bot.uin })
+ redis.set(this.MuteTaskKey, JSON.stringify(redisTask))
+ return true
+ }
+
+ /**
+ * @description 从 Redis 中获取群禁言/解禁任务列表,并将其转换为定时任务列表
+ * @returns {Promise} - 返回转换后的定时任务列表,列表中的每一项都包含 cron、name 和 fnc 三个属性。其中,cron 表示任务的执行时间;name 表示任务的名称;fnc 表示任务的执行函数。
+ */
+ static async getRedisMuteTask () {
+ return JSON.parse(await redis.get('yenai:MuteTasks'))?.map(item => {
+ return {
+ cron: item.cron,
+ name: `椰奶群定时${item.type ? '禁言' : '解禁'}${item.group}`,
+ fnc: () => {
+ (Bot[item.botId] ?? Bot).pickGroup(Number(item.group)).muteAll(item.type)
+ }
+ }
+ })
+ }
+
+ /**
+ * @description 删除指定的群禁言/解禁任务
+ * @param {string} group - 群号
+ * @param {boolean} type - 是否为禁言任务。如果为 true,则表示禁言任务;否则,表示解禁任务。
+ * @returns {Promise} - 返回操作结果。如果删除成功,则返回 true。
+ */
+ async delMuteTask (group, type) {
+ let redisTask = JSON.parse(await redis.get(this.MuteTaskKey)) || []
+ loader.task = loader.task.filter(item => item.name !== `椰奶群定时${type ? '禁言' : '解禁'}${group}`)
+ redisTask = redisTask.filter(item => item.group !== group && item.type !== type)
+ redis.set(this.MuteTaskKey, JSON.stringify(redisTask))
+ return true
+ }
+
+ /** 获取定时任务 */
+ getMuteTask () {
+ let RegEx = /椰奶群定时(禁言|解禁)(\d+)/
+ let taskList = _.cloneDeep(loader.task)
+ let MuteList = taskList.filter(item => /椰奶群定时禁言\d+/.test(item.name))
+ let noMuteList = taskList.filter(item => /椰奶群定时解禁\d+/.test(item.name))
+ noMuteList.forEach(noitem => {
+ let index = MuteList.findIndex(item => noitem.name.match(RegEx)[2] == item.name.match(RegEx)[2])
+ if (index !== -1) {
+ MuteList[index].nocron = noitem.cron
+ } else {
+ noitem.nocron = noitem.cron
+ delete noitem.cron
+ MuteList.push(noitem)
+ }
+ })
+ return MuteList.map(item => {
+ let analysis = item.name.match(RegEx)
+ return [
+ segment.image(`https://p.qlogo.cn/gh/${analysis[2]}/${analysis[2]}/100`),
+ `\n群号:${analysis[2]}`,
+ item.cron ? `\n禁言时间:'${item.cron}'` : '',
+ item.nocron ? `\n解禁时间:'${item.nocron}'` : ''
+ ]
+ })
+ }
+
+ /**
+ * @async
+ * @function muteMember
+ * @description 将群成员禁言
+ * @param {string|number} groupId - 群号
+ * @param {string|number} userId - QQ 号
+ * @param {string|number} executor - 执行操作的管理员 QQ 号
+ * @param {number} [time=5] - 禁言时长,默认为 5。如果传入 0 则表示解除禁言。
+ * @param {string} [unit='分'] - 禁言时长单位,默认为分钟
+ * @returns {Promise} - 返回操作结果
+ * @throws {Error} - 如果缺少必要参数或参数格式不正确,则会抛出错误
+ */
+ async muteMember (groupId, userId, executor, time = 300, unit = '秒') {
+ unit = Time_unit[unit.toUpperCase()] ?? (/^\d+$/.test(unit) ? unit : 60)
+ let group = this.Bot.pickGroup(Number(groupId), true)
+ // 判断是否有管理
+ if (!group.is_admin && !group.is_owner) throw Error(ROLE_ERROR)
+ if (!(/\d{5,}/.test(userId))) throw Error('❎ 请输入正确的QQ号')
+ // 判断是否为主人
+ if (Config.masterQQ?.includes(Number(userId)) && time != 0) throw Error('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
+
+ let Memberinfo = group.pickMember(Number(userId)).info
+ // 判断是否有这个人
+ if (!Memberinfo) throw Error('❎ 这个群没有这个人哦~')
+
+ // 特殊处理
+ if (Memberinfo.role === 'owner') throw Error('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
+
+ let user = group.pickMember(Number(executor))
+ let isMaster = Config.masterQQ?.includes(executor)
+
+ if (Memberinfo.role === 'admin') {
+ if (!group.is_owner) throw Error('人家又不是群主这种事做不到的辣!')
+ if (!isMaster && !user.member.is_owner) throw Error('这个淫系管理员辣,只有主淫和群主才可以干ta')
+ }
+
+ await group.muteMember(userId, time * unit)
+ return time == 0 ? `✅ 已把「${Memberinfo.card || Memberinfo.nickname}」从小黑屋揪了出来(。>∀<。)` : `已把「${Memberinfo.card || Memberinfo.nickname}」扔进了小黑屋( ・_・)ノ⌒●~*`
+ }
+
+ /**
+ * @description: 踢群成员
+ * @param {Number} groupId 群号
+ * @param {Number} userId 被踢人
+ * @param {Number} executor 执行人
+ * @return {Promise}
+ */
+ async kickMember (groupId, userId, executor) {
+ let group = null
+ group = this.Bot.pickGroup(Number(groupId), true)
+
+ if (!userId || !(/^\d+$/.test(userId))) throw Error('❎ 请输入正确的QQ号')
+ if (!groupId || !(/^\d+$/.test(groupId))) throw Error('❎ 请输入正确的群号')
+ // 判断是否为主人
+ if (Config.masterQQ?.includes(Number(userId))) throw Error('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
+
+ let Memberinfo = group?.pickMember(Number(userId)).info
+ // 判断是否有这个人
+ if (!Memberinfo) throw Error('❎ 这个群没有这个人哦~')
+ if (Memberinfo.role === 'owner') throw Error('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
+ let isMaster = Config.masterQQ?.includes(executor)
+ let user = group.pickMember(Number(executor))
+ if (Memberinfo.role === 'admin') {
+ if (!group.is_owner) throw Error('人家又不是群主这种事做不到的辣!')
+ if (!isMaster && !user.is_owner) throw Error('这个淫系管理员辣,只有主淫和群主才可以干ta')
+ }
+ let res = await group.kickMember(Number(userId))
+ if (!res) throw Error('额...踢出失败哩,可能这个淫比较腻害>_<')
+ return '已把这个坏淫踢掉惹!!!'
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/model/GroupBannedWords.js b/Yunzai/plugins/yenai-plugin/model/GroupBannedWords.js
new file mode 100644
index 0000000000000000000000000000000000000000..2829542e6d53b550d9ff1f685a4cbe5080b8acd0
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/GroupBannedWords.js
@@ -0,0 +1,179 @@
+import _ from 'lodash'
+import moment from 'moment'
+import { Data, Plugin_Path } from '../components/index.js'
+
+export default new class {
+ constructor () {
+ this.root = `${Plugin_Path}/config/group`
+ this.penaltyTypeMap = {
+ 1: '踢',
+ 2: '禁',
+ 3: '撤',
+ 4: '踢撤',
+ 5: '禁撤'
+ }
+ this.matchTypeMap = {
+ 1: '精确',
+ 2: '模糊',
+ 3: '正则'
+ }
+ this.dataCach = new Map()
+ this.muteTimeCach = new Map()
+ this.groupTitleCach = new Map()
+ }
+
+ addBannedWords (
+ groupId, words, matchType = '精确', penaltyType = '禁', addedBy
+ ) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ if (!data.bannedWords) data.bannedWords = {}
+ if (data.bannedWords[words]) throw Error(`❎ 违禁词${words}已存在`)
+ // 翻转对象
+ let matchTypeMapMirr = _.invert(this.matchTypeMap)
+ let penaltyTypeMapMirr = _.invert(this.penaltyTypeMap)
+ data.bannedWords[words] = {
+ matchType: Number(matchTypeMapMirr[matchType]),
+ penaltyType: Number(penaltyTypeMapMirr[penaltyType]),
+ date: moment().format('MMM Do YY'),
+ addedBy
+ }
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ this.dataCach.delete(groupId)
+ return {
+ words: this.keyWordTran(words),
+ matchType,
+ penaltyType
+ }
+ }
+
+ delBannedWords (groupId, words) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ if (!data.bannedWords[words]) throw Error(`❎ 违禁词${words}不存在`)
+ delete data.bannedWords[words]
+ this.dataCach.delete(groupId)
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ return this.keyWordTran(words)
+ }
+
+ queryBannedWords (groupId, words) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ if (!data.bannedWords[words]) throw Error(`❎ 违禁词${words}不存在`)
+ let { matchType, penaltyType } = data.bannedWords[words]
+ return {
+ ...data.bannedWords[words],
+ words: this.keyWordTran(words),
+ matchType: this.matchTypeMap[matchType],
+ penaltyType: this.penaltyTypeMap[penaltyType]
+ }
+ }
+
+ setMuteTime (groupId, time) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ data.muteTime = Number(time)
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ this.muteTimeCach.delete(groupId)
+ return true
+ }
+
+ getMuteTime (groupId) {
+ if (this.muteTimeCach.get(groupId)) return this.muteTimeCach.get(groupId)
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ this.muteTimeCach.set(groupId, data.muteTime ?? 300)
+ return data.muteTime ?? 300
+ }
+
+ /** 关键词转换成可发送消息 */
+ async keyWordTran (msg) {
+ /** 图片 */
+ if (msg.includes('{image')) {
+ let tmp = msg.split('{image')
+ if (tmp.length > 2) return false
+
+ let md5 = tmp[1].replace(/}|_|:/g, '')
+
+ msg = segment.image(`http://gchat.qpic.cn/gchatpic_new/0/0-0-${md5}/0`)
+ msg.asface = true
+ } else if (msg.includes('{at:')) {
+ let tmp = msg.match(/{at:(.+?)}/g)
+
+ for (let qq of tmp) {
+ qq = qq.match(/[1-9][0-9]{4,14}/g)[0]
+ let member = await Bot.getGroupMemberInfo(this.group_id, Number(qq)).catch(() => { })
+ let name = member?.card ?? member?.nickname
+ if (!name) continue
+ msg = msg.replace(`{at:${qq}}`, `@${name}`)
+ }
+ } else if (msg.includes('{face')) {
+ let tmp = msg.match(/{face(:|_)(.+?)}/g)
+ if (!tmp) return msg
+ msg = []
+ for (let face of tmp) {
+ let id = face.match(/\d+/g)
+ msg.push(segment.face(id))
+ }
+ }
+
+ return msg
+ }
+
+ /** 初始化已添加内容 */
+ initTextArr (groupId) {
+ if (this.dataCach.get(groupId)) return this.dataCach.get(groupId)
+
+ try {
+ const data = Data.readJSON(`${groupId}.json`, this.root)?.bannedWords
+ const _data = new Map()
+ for (const item in data) {
+ data[item].rawItem = item
+ if (data[item].matchType == 2) {
+ _data.set(new RegExp(item), data[item])
+ } else if (data[item].matchType == 3) {
+ _data.set(global.eval(item), data[item])
+ } else {
+ _data.set(new RegExp(`^${item}$`), data[item])
+ }
+ }
+ this.dataCach.set(groupId, _data)
+ return _data
+ } catch (error) {
+ logger.error(error)
+ logger.error(`json格式错误:${this.root}/${groupId}.json`)
+ delete this.dataCach[groupId]
+ return false
+ }
+ }
+
+ setTitleFilterModeChange (groupId) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ data.TitleFilterModeChange = data.TitleFilterModeChange ? 0 : 1
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ return data.TitleFilterModeChange
+ }
+
+ getTitleFilterModeChange (groupId) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ return data.TitleFilterModeChange ?? 0
+ }
+
+ addTitleBannedWords (groupId, arr) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ if (!data.TitleBannedWords)data.TitleBannedWords = []
+ data.TitleBannedWords.push(...arr)
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ this.groupTitleCach.delete(groupId)
+ }
+
+ getTitleBannedWords (groupId) {
+ if (this.groupTitleCach.get(groupId)) return this.groupTitleCach.get(groupId)
+ let data = Data.readJSON(`${groupId}.json`, this.root).TitleBannedWords ?? []
+ this.groupTitleCach.set(groupId, data)
+ return data
+ }
+
+ delTitleBannedWords (groupId, arr) {
+ let data = Data.readJSON(`${groupId}.json`, this.root)
+ data.TitleBannedWords = _.differenceBy(data.TitleBannedWords, arr)
+ Data.writeJSON(`${groupId}.json`, data, this.root)
+ this.groupTitleCach.delete(groupId)
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/model/PicSearch/ascii2d.js b/Yunzai/plugins/yenai-plugin/model/PicSearch/ascii2d.js
new file mode 100644
index 0000000000000000000000000000000000000000..0196b04f8188668c754c73ec4b85d44f9fd0aa84
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/PicSearch/ascii2d.js
@@ -0,0 +1,109 @@
+/* eslint-disable no-unused-vars */
+import _ from 'lodash'
+import { puppeteer } from '../index.js'
+import request from '../../lib/request/request.js'
+import { Config } from '../../components/index.js'
+let cheerio = ''
+
+let domain = 'https://ascii2d.net/'
+
+async function importCheerio () {
+ if (cheerio) return cheerio
+ try {
+ cheerio = await import('cheerio')
+ } catch (e) {
+ throw Error('未检测到依赖cheerio,请安装后再使用Ascii2D搜图,安装命令:pnpm add cheerio -w 或 pnpm install -P')
+ }
+}
+
+export default async function doSearch (url) {
+ await importCheerio()
+ const { ascii2dUsePuppeteer, ascii2dResultMaxQuantity } = Config.picSearch
+ const callApi = ascii2dUsePuppeteer ? callAscii2dUrlApiWithPuppeteer : callAscii2dUrlApi
+ let ret = await callApi(url)
+ if (!ret) throw Error('Ascii2D搜图请求失败')
+ const colorURL = ret.url
+ if (!colorURL.includes('/color/')) {
+ const $ = cheerio.load(ret.data, { decodeEntities: false })
+ logger.error('[error] ascii2d url:', colorURL)
+ logger.debug(ret.data)
+ let isCloudflare = ret.data.includes('cloudflare') ? '绕过Cloudflare盾失败' : false
+ throw Error(`Ascii2D搜索失败,错误原因:${isCloudflare || $('.container > .row > div:first-child > p').text().trim()}`)
+ }
+ const bovwURL = colorURL.replace('/color/', '/bovw/')
+ let bovwDetail = await (ascii2dUsePuppeteer ? getAscii2dWithPuppeteer(bovwURL) : request.cfGet(bovwURL))
+ if (!ascii2dUsePuppeteer) {
+ bovwDetail = {
+ url: bovwDetail.url,
+ data: await bovwDetail.text()
+ }
+ }
+ let colorData = (await parse(ret.data)).slice(0, ascii2dResultMaxQuantity)
+ let bovwData = (await parse(bovwDetail.data)).slice(0, ascii2dResultMaxQuantity)
+ if (_.isEmpty(colorData)) throw Error('Ascii2D数据获取失败')
+ let mapfun = item => [
+ Config.picSearch.hideImg ? '' : segment.image(item.image),
+ `${item.info}\n`,
+ `标题:${item.source?.text}\n`,
+ `作者:${item.author?.text}(${item.author?.link})\n`,
+ `来源:${item.source?.link}`
+ ]
+ let color = colorData.map(mapfun)
+ let bovw = bovwData.map(mapfun)
+
+ color.unshift('ascii2d 色合検索')
+ bovw.unshift('ascii2d 特徴検索')
+ return {
+ color,
+ bovw
+ }
+}
+const callAscii2dUrlApiWithPuppeteer = (imgUrl) => {
+ return getAscii2dWithPuppeteer(`${domain}/search/url/${imgUrl}`)
+}
+const callAscii2dUrlApi = async (imgUrl) => {
+ let res = await request.cfGet(`${domain}/search/url/${imgUrl}`).catch(
+ err => {
+ if (err.stack?.includes('legacy sigalg disallowed or unsupported')) {
+ throw Error(`Error Tls版本过低 请尝试将配置文件的‘cfTLSVersion’字段改为‘TLS1.2’\n详情请参考:https://www.yenai.ren/faq.html#openssl-%E9%94%99%E8%AF%AF\n错误信息:${err.stack}`)
+ } else {
+ throw err
+ }
+ }
+ )
+ return {
+ url: res.url,
+ data: await res.text()
+ }
+}
+async function getAscii2dWithPuppeteer (url) {
+ return await puppeteer.get(url, 'body > .container')
+}
+async function parse (body) {
+ const $ = cheerio.load(body, { decodeEntities: true })
+ return _.map($('.item-box'), (item) => {
+ const detail = $('.detail-box', item)
+ const hash = $('.hash', item)
+ const info = $('.info-box > .text-muted', item)
+ const [image] = $('.image-box > img', item)
+
+ const [source, author] = $('a[rel=noopener]', detail)
+
+ if (!source && !author) return
+
+ return {
+ hash: hash.text(),
+ info: info.text(),
+ image: new URL(
+ image.attribs.src ?? image.attribs['data-cfsrc'],
+ domain
+ ).toString(),
+ source: source
+ ? { link: source.attribs.href, text: $(source).text() }
+ : undefined,
+ author: author
+ ? { link: author.attribs.href, text: $(author).text() }
+ : undefined
+ }
+ }).filter(v => v !== undefined)
+}
diff --git a/Yunzai/plugins/yenai-plugin/model/PicSearch/saucenao.js b/Yunzai/plugins/yenai-plugin/model/PicSearch/saucenao.js
new file mode 100644
index 0000000000000000000000000000000000000000..5d4c856331eb1acc2c4e38bcbb979d6bf2a48f72
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/PicSearch/saucenao.js
@@ -0,0 +1,74 @@
+import _ from 'lodash'
+import { Config } from '../../components/index.js'
+import sagiri from '../../tools/sagiri.js'
+import request from '../../lib/request/request.js'
+import Ascii2D from './ascii2d.js'
+export default async function doSearch (url) {
+ let res = await getSearchResult(url)
+ logger.debug('SauceNAO result:', res)
+ if (res.header.status != 0) throw Error('SauceNAO搜图,错误信息:' + res.header.message?.replace(/<.*?>/g, ''))
+ let format = sagiri(res)
+ if (_.isEmpty(format)) throw Error('SauceNAO搜图无数据')
+
+ let msgMap = async item => [
+ `SauceNAO (${item.similarity}%)\n`,
+ Config.picSearch.hideImg ? '' : await request.proxyRequestImg(item.thumbnail),
+ `图源:${item.site}\n`,
+ `作者:${item.authorName}(${item.authorUrl})\n`,
+ `来源:${item.url.toString()}`
+ ]
+ let maxSimilarity = format[0].similarity
+ let filterSimilarity = format.filter(item => item.similarity > 80)
+ let message = []
+ if (!_.isEmpty(filterSimilarity)) {
+ let filterPixiv = filterSimilarity.filter(item => item.site == 'Pixiv')
+ if (!_.isEmpty(filterPixiv)) {
+ message.push(await msgMap(filterPixiv[0]))
+ } else {
+ message.push(await msgMap(filterSimilarity[0]))
+ }
+ } else {
+ message = await Promise.all(format.map(msgMap))
+ }
+ let n = maxSimilarity > 80 ? '\n' : ''
+ if (res.header.long_remaining < 30) {
+ const msg = `${n}SauceNAO 24h 内仅剩 ${res.header.long_remaining} 次使用次数`
+ n ? message[0].push(msg) : message.push(msg)
+ }
+ if (res.header.short_remaining < 3) {
+ const msg = `${n}SauceNAO 30s 内仅剩 ${res.header.short_remaining} 次。`
+ n ? message[0].push(msg) : message.push(msg)
+ }
+ let { SauceNAOMinSim, useAscii2dWhenLowAcc } = Config.picSearch
+ if ((maxSimilarity < SauceNAOMinSim) && useAscii2dWhenLowAcc) {
+ message.push(`SauceNAO 相似度 ${maxSimilarity}% 过低,使用Ascii2D进行搜索`)
+ await Ascii2D(url)
+ .then(res => message.push(...res.color, ...res.bovw))
+ .catch(err => message.push(err.stack))
+ }
+ return message
+}
+
+async function getSearchResult (imgURL, db = 999) {
+ logger.debug(`saucenao [${imgURL}]}`)
+ let api_key = Config.picSearch.SauceNAOApiKey
+ if (!api_key) throw Error('未配置SauceNAOApiKey,无法使用SauceNAO搜图,请在 https://saucenao.com/user.php?page=search-api 进行获取,请用指令:#设置SauceNAOapiKey 进行添加')
+ return await request.get('https://saucenao.com/search.php', {
+ params: {
+ api_key,
+ db,
+ output_type: 2,
+ numres: 3,
+ url: imgURL,
+ hide: Config.picSearch.hideImgWhenSaucenaoNSFW
+ },
+ closeCheckStatus: true,
+ timeout: 60000
+ }).then(res => {
+ if (res.status === 429) {
+ throw Error('SauceNAO搜图 搜索次数已达单位时间上限,请稍候再试')
+ } else {
+ return res.json()
+ }
+ })
+}
diff --git a/Yunzai/plugins/yenai-plugin/model/PicSearch/whatanime.js b/Yunzai/plugins/yenai-plugin/model/PicSearch/whatanime.js
new file mode 100644
index 0000000000000000000000000000000000000000..efd10dcbd8d6eba4444684eda70f935bf7a455ea
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/PicSearch/whatanime.js
@@ -0,0 +1,112 @@
+import request from '../../lib/request/request.js'
+import { Config, Plugin_Path } from '../../components/index.js'
+import common from '../../../../lib/common/common.js'
+import _ from 'lodash'
+export default async function doSearch (imgURL) {
+ let result = await getSearchResult(imgURL)
+ if (result.error) throw Error(result.error)
+
+ let {
+ result: [{
+ similarity,
+ anilist, // 番剧 ID
+ episode = '-', // 集数
+ from, // 时间点
+ video // 预览视频
+ // image // 预览图片
+ }]
+ } = result
+ if (_.isEmpty(result)) throw Error('未获取到相关信息')
+ similarity = (similarity * 100).toFixed(2) // 相似度
+ const time = (() => {
+ const s = Math.floor(from)
+ const m = Math.floor(s / 60)
+ const ms = [m, s % 60]
+ return ms.map(num => String(num).padStart(2, '0')).join(':')
+ })()
+ const AnimeInfo = await getAnimeInfo(anilist)
+ const { type, format, isAdult, title, startDate, endDate, coverImage } = AnimeInfo.data.Media
+ const { hideImg, hideImgWhenWhatanimeR18, whatanimeSendVideo } = Config.picSearch
+ let msg = [
+ `WhatAnime (${similarity}%)\n该截图出自第${episode}集的${time}\n`
+ ]
+ if (!(hideImg || (hideImgWhenWhatanimeR18 && isAdult))) {
+ msg.push(segment.image(coverImage.large))
+ }
+ const titles = _.uniq(['romaji', 'native', 'chinese'].map(k => title[k]).filter(v => v))
+ msg.push(titles.join('\n'), `\n类型:${type}-${format}`, `\n开播:${date2str(startDate)}`)
+ if (endDate.year > 0) msg.push(`\n完结:${date2str(endDate)}`)
+ if (isAdult) msg.push('\nR18注意!')
+ let msgs = [msg]
+ if (!isAdult && whatanimeSendVideo) {
+ msgs.push(await downFile(video))
+ }
+ return msgs
+}
+
+const date2str = ({ year, month, day }) => [year, month, day].join('-')
+/**
+ * 取得搜番结果
+ *
+ * @param {string} host 自定义 whatanime 的 host
+ * @param {string} key whatanime token
+ * @param {string} url 图片地址
+ * @returns Prased JSON
+ */
+async function getSearchResult (url, key = '') {
+ let host = 'https://api.trace.moe'
+ return await request.get(`${host}/search`, {
+ params: {
+ url,
+ key
+ }
+ }).then(res => res.json())
+}
+const animeInfoQuery = `
+query ($id: Int) {
+ Media (id: $id, type: ANIME) {
+ id
+ type
+ format
+ isAdult
+ title {
+ native
+ romaji
+ }
+ startDate {
+ year
+ month
+ day
+ }
+ endDate {
+ year
+ month
+ day
+ }
+ coverImage {
+ large
+ }
+ }
+}`
+/**
+ * 取得番剧信息
+ *
+ * @param {number} id
+ * @returns Prased JSON
+ */
+async function getAnimeInfo (id) {
+ return await request.post('https://trace.moe/anilist/', {
+ data: {
+ query: animeInfoQuery,
+ variables: { id }
+ }
+ }).then(res => res.json())
+}
+
+async function downFile (url) {
+ let path = `${Plugin_Path}/temp/whatanime/1.mp4`
+ logger.mark('[Yenai-Plugin][whatanime]下载预览视频')
+ await common.downFile(url, path)
+ logger.mark('[Yenai-Plugin][whatanime]下载预览视频成功')
+ return segment.video(path)
+}
diff --git a/Yunzai/plugins/yenai-plugin/model/Pixiv.js b/Yunzai/plugins/yenai-plugin/model/Pixiv.js
new file mode 100644
index 0000000000000000000000000000000000000000..0ffe86ebfdae06525982a968b7729a5526462e35
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/Pixiv.js
@@ -0,0 +1,550 @@
+import _ from 'lodash'
+import moment from 'moment'
+import fetch from 'node-fetch'
+import { Config } from '../components/index.js'
+import request from '../lib/request/request.js'
+import { rankType } from '../constants/pixiv.js'
+import { pixivMsg } from '../constants/msg.js'
+import PixivApi from './Pixiv/api.js'
+/** API请求错误文案 */
+
+export default new class Pixiv {
+ constructor () {
+ this.ranktype = rankType
+ this.domain = 'http://api.obfs.dev/api/pixiv'
+ this.PixivClient = new PixivApi(Config.pixiv.refresh_token)
+ }
+
+ async loginInfo () {
+ if (!this.PixivClient?.auth) {
+ await this.PixivClient.login()
+ }
+ if (!this.PixivClient.auth?.user) throw Error('❎ 未获取到登录信息')
+ const { profile_image_urls: { px_170x170 }, id, name, account, mail_address, is_premium, x_restrict } = this.PixivClient.auth.user
+ return [
+ await this._requestPixivImg(px_170x170),
+ `\nid:${id}\n`,
+ `name:${name}\n`,
+ `account:${account}\n`,
+ `mail_address:${mail_address}\n`,
+ `is_premium:${is_premium}\n`,
+ `x_restrict:${x_restrict}`
+ ]
+ }
+
+ get headers () {
+ if (Config.pixiv.pixivDirectConnection) {
+ return {
+ 'Host': 'i.pximg.net',
+ 'Referer': 'https://www.pixiv.net/',
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.46'
+ }
+ } else {
+ return undefined
+ }
+ }
+
+ get proxy () {
+ return Config.pixiv.pixivDirectConnection ? 'i.pximg.net' : Config.pixiv.pixivImageProxy
+ }
+
+ /** 开始执行文案 */
+ get startMsg () {
+ return _.sample(pixivMsg.start)
+ }
+
+ /**
+ * @description: 获取插画信息
+ * @param {String} ids 插画ID
+ * @return {Object}
+ */
+ async illust (ids, filter = false) {
+ const params = { id: ids }
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.illust(params)
+ } else {
+ res = await request.get(`${this.domain}/illust`, { params }).then(res => res.json())
+ }
+ if (res.error) throw Error(res.error?.user_message || '无法获取数据')
+ let illust = this._format(res.illust)
+ let { id, title, user, tags, total_bookmarks, total_view, url, create_date, x_restrict, illust_ai_type } = illust
+ let msg = [
+ `标题:${title}\n`,
+ `画师:${user.name}\n`,
+ `PID:${id}\n`,
+ `UID:${user.id}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `访问:${total_view}\n`,
+ `isAI:${illust_ai_type == 2}\n`,
+ `发布:${moment(create_date).format('YYYY-MM-DD HH:mm:ss')}\n`,
+ `Tag:${tags.join(',')}\n`,
+ `直链:https://pixiv.re/${id}.jpg\n`,
+ `传送门:https://www.pixiv.net/artworks/${id}`
+ ]
+ if (filter && x_restrict) {
+ let linkmsg = ['该作品不适合所有年龄段,请自行使用链接查看:']
+ if (url.length > 1) {
+ linkmsg.push(...url.map((item, index) => `https://pixiv.re/${id}-${index + 1}.jpg`))
+ } else {
+ linkmsg.push(`https://pixiv.re/${id}.jpg`)
+ }
+ throw Error(linkmsg.join('\n'))
+ }
+ let img = await Promise.all(url.map(async item => await this._requestPixivImg(item)))
+ return { msg, img }
+ }
+
+ /**
+ * @description: 获取Pixiv榜单
+ * @param {Number} page 页数
+ * @param {Date} date 时间YYYY-MM-DD
+ * @param {String} mode 榜单类型
+ * @param {Boolean} r18 是否为R18榜单
+ * @return {Array}
+ */
+ async Rank (page = 1, date = '', mode = '周', r18 = false) {
+ // 转为大写
+ mode = _.toUpper(mode)
+ // 排行榜类型
+ let type = this.ranktype[mode].type
+ // 总张数
+ let pageSizeAll = this.ranktype[mode].total
+ // r18处理
+ if (r18) {
+ let R18 = this.ranktype[mode].r18
+ if (!R18) throw Error('该排行没有不适合所有年龄段的分类哦~')
+ type = R18.type
+ pageSizeAll = R18.total
+ }
+ // 总页数
+ let pageAll = Math.ceil(pageSizeAll / 30)
+ if (page > pageAll) throw Error('哪有那么多图片给你辣(•̀へ •́ ╮ )')
+
+ if (!date) date = moment().subtract(moment().utcOffset(9).hour() >= 12 ? 1 : 2, 'days').format('YYYY-MM-DD')
+
+ const params = {
+ mode: type,
+ page,
+ date
+ }
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.rank(params)
+ } else {
+ res = await request.get(`${this.domain}/rank`, { params }).then(res => res.json())
+ }
+ if (res.error) throw Error(res.error.message)
+ if (_.isEmpty(res.illusts)) throw Error('暂无数据,请等待榜单更新哦(。-ω-)zzz')
+
+ let illusts = await Promise.all(res.illusts.map(async (item, index) => {
+ let list = this._format(item)
+ let { id, title, user, tags, total_bookmarks, image_urls } = list
+ return [
+ `标题:${title}\n`,
+ `画师:${user.name}\n`,
+ `PID:${id}\n`,
+ `UID:${user.id}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `排名:${(page - 1) * 30 + (index + 1)}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ await this._requestPixivImg(image_urls.large)
+ ]
+ }))
+ let formatDate = res.next_url.match(/date=(\d{4}-\d{1,2}-\d{1,2})/)[1]
+ formatDate = moment(formatDate, 'YYYY-MM-DD').format('YYYY年MM月DD日')
+ if (/周/.test(mode)) {
+ formatDate = `${moment(formatDate, 'YYYY年MM月DD日').subtract(6, 'days').format('YYYY年MM月DD日')} ~ ${formatDate}`
+ } else if (/月/.test(mode)) {
+ formatDate = `${moment(formatDate, 'YYYY年MM月DD日').subtract(29, 'days').format('YYYY年MM月DD日')} ~ ${formatDate}`
+ }
+ let list = [
+ `${formatDate}的${mode}${r18 ? 'R18' : ''}榜`,
+ `当前为第${page}页,共${pageAll}页,本页共${illusts.length}张,总共${pageSizeAll}张`
+ ]
+ if (page < pageAll) {
+ list.push(`可使用 "#看看${date ? `${formatDate}的` : ''}${mode}${r18 ? 'R18' : ''}榜第${page - 0 + 1}页" 翻页`)
+ }
+
+ list.push(...illusts)
+ return list
+ }
+
+ /**
+ * @description: 根据关键词搜图
+ * @param {String} tag 关键词
+ * @param {String} page 页数
+ * @return {Array}
+ */
+ async vilipixSearchTags (tag, page = 1) {
+ const api = 'https://www.vilipix.com/api/v1/picture/public'
+ const params = {
+ limit: 30,
+ tags: tag,
+ sort: 'new',
+ offset: (page - 1) * 30
+ }
+ let res = await request.get(api, { params }).then(res => res.json())
+ if (res.data.count == 0) throw Error('呜呜呜,人家没有找到相关的插画(ó﹏ò。)')
+
+ let pageall = Math.ceil(res.data.count / 30)
+
+ if (page > pageall) throw Error('啊啊啊,淫家给不了你那么多辣d(ŐдŐ๑)')
+
+ let list = [
+ `当前为第${page}页,共${pageall}页,本页共${res.data.rows.length}张,总共${res.data.count}张`
+ ]
+ if (page < pageall) {
+ list.push(`可使用 "#tag搜图${tag}第${page - 0 + 1}页" 翻页`)
+ }
+ res.data.rows.sort((a, b) => b.like_total - a.like_total)
+ for (let i of res.data.rows) {
+ let { picture_id, title, original_url, tags } = i
+ list.push([
+ `标题:${title}\n`,
+ `PID:${picture_id}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ segment.image(original_url)
+ ])
+ }
+ return list
+ }
+
+ /**
+ * @description: tag搜图pro
+ * @param {String} tag 关键词
+ * @param {String} page 页数
+ * @return {*}
+ */
+ async searchTags (tag, page = 1, isfilter = true) {
+ const params = {
+ word: tag,
+ page,
+ order: 'popular_desc'
+ }
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.search(params)
+ } else {
+ res = await request.get(`${this.domain}/search`, { params }).then(res => res.json())
+ }
+ if (res.error) throw Error(res.error.message)
+ if (_.isEmpty(res.illusts)) throw Error('宝~没有数据了哦(๑>︶<)و')
+ let sortIllusts = _.orderBy(res.illusts, 'total_bookmarks', 'desc')
+ let illusts = []
+ let filterNum = 0
+ let NowNum = res.illusts.length
+ for (let i of sortIllusts) {
+ let { id, title, user, tags, total_bookmarks, image_urls, x_restrict } = this._format(i)
+ if (isfilter && x_restrict) {
+ filterNum++
+ continue
+ }
+ illusts.push([
+ `标题:${title}\n`,
+ `画师:${user.name}\n`,
+ `PID:${id}\n`,
+ `UID:${user.id}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ await this._requestPixivImg(image_urls.large)
+ ])
+ }
+ if (_.isEmpty(illusts)) throw Error('该页全为涩涩内容已全部过滤(#/。\#)')
+
+ return [
+ `本页共${NowNum}张${filterNum ? `,过滤${filterNum}张` : ''}\n可尝试使用 "#tagpro搜图${tag}第${page - 0 + 1}页" 翻页\n无数据则代表无下一页`,
+ ...illusts
+ ]
+ }
+
+ /**
+ * @description: 获取热门tag
+ * @return {Array}
+ */
+ async PopularTags () {
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.tags()
+ } else {
+ res = await fetch(`${this.domain}/tags`).then(res => res.json())
+ }
+
+ if (!res.trend_tags) throw Error('呜呜呜,没有获取到数据(๑ १д१)')
+
+ let list = []
+ for (let i of res.trend_tags) {
+ let { tag, translated_name } = i
+ let url = i.illust.image_urls.large
+ list.push(
+ [
+ `Tag:${tag}\n`,
+ `Translated:${translated_name}\n`,
+ `Pid:${i.illust.id}\n`,
+ await this._requestPixivImg(url)
+ ]
+ )
+ }
+ return list
+ }
+
+ /**
+ * @description: 搜索用户插画
+ * @param {Number|String} keyword 用户uid或名称
+ * @param {Number|String} page 页数
+ * @param {Boolean} isfilter 是否过滤敏感内容
+ * @return {Array}
+ */
+ async userIllust (keyword, page = 1, isfilter = true) {
+ // 关键词搜索
+ if (!/^\d+$/.test(keyword)) {
+ let wordlist = null
+ if (this.PixivClient.auth) {
+ wordlist = await this.PixivClient.search_user({ word: keyword })
+ } else {
+ wordlist = await request.get(`${this.domain}/search_user`, {
+ params: {
+ word: keyword
+ }
+ }).then(res => res.json())
+ }
+ if (_.isEmpty(wordlist.user_previews)) throw Error('呜呜呜,人家没有找到这个淫d(ŐдŐ๑)')
+ keyword = wordlist.user_previews[0].user.id
+ }
+ const params = {
+ id: keyword,
+ page
+ }
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.member_illust(params)
+ } else {
+ res = await request.get(`${this.domain}/member_illust`, { params }).then(res => res.json())
+ }
+
+ if (res.error) throw Error(res.error.message)
+ // 没有作品直接返回信息
+ if (_.isEmpty(res.illusts)) throw Error(page >= 2 ? '这一页没有作品辣(>人<;)' : 'Σ(っ °Д °;)っ这个淫居然没有作品')
+
+ let illusts = []
+ let filter = 0
+ let NowNum = res.illusts.length
+ for (let i of res.illusts) {
+ let { id: pid, title, tags, total_bookmarks, total_view, url, x_restrict } = this._format(i)
+ if (isfilter && x_restrict) {
+ filter++
+ continue
+ }
+ illusts.push([
+ `标题:${title}\n`,
+ `PID:${pid}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `访问:${total_view}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ await this._requestPixivImg(url[0])
+ ])
+ }
+ if (_.isEmpty(illusts)) throw Error('该页全为涩涩内容已全部过滤(#/。\#)')
+ let { id: uid, name, profile_image_urls } = res.user
+ return [
+ [
+ await this._requestPixivImg(profile_image_urls.medium),
+ `\nUid:${uid}\n`,
+ `画师:${name}`
+ ],
+ `本页共${NowNum}张${filter ? `,过滤${filter}张` : ''}\n可尝试使用 "#uid搜图${keyword}第${page - 0 + 1}页" 翻页\n无数据则代表无下一页`,
+ ...illusts
+ ]
+ }
+
+ /**
+ * @description:搜索用户
+ * @param {String} word 用户name
+ * @param {Number} page 页数
+ * @param {Boolean} isfilter 是否过滤敏感内容
+ * @return {Array} 可直接发送的消息数组
+ */
+ async searchUser (word, page = 1, isfilter = true) {
+ let params = {
+ word,
+ page,
+ size: 10
+ }
+ let user = null
+ if (this.PixivClient.auth) {
+ user = await this.PixivClient.search_user(params)
+ } else {
+ user = await request.get(`${this.domain}/search_user`, { params }).then(res => res.json())
+ }
+ if (user.error) throw Error(user.error.message)
+ if (_.isEmpty(user.user_previews)) throw Error('呜呜呜,人家没有找到这个淫d(ŐдŐ๑)')
+
+ let msg = await Promise.all(user.user_previews.slice(0, 10).map(async (item, index) => {
+ let { id, name, profile_image_urls } = item.user
+ let ret = [
+ `${(page - 1) * 10 + index + 1}、`,
+ await this._requestPixivImg(profile_image_urls),
+ `\nid: ${id}\n`,
+ `name: ${name}\n`,
+ '作品:\n'
+ ]
+ for (let i of item.illusts) {
+ let { image_urls, x_restrict } = this._format(i)
+ if (isfilter && x_restrict) continue
+ ret.push(await this._requestPixivImg(image_urls.square_medium))
+ }
+ return ret
+ }))
+ if (msg.length == 30)msg.unshift(`可尝试使用 "#user搜索${word}第${page + 1}页" 翻页`)
+ msg.unshift(`当前为第${page}页,已${isfilter ? '开启' : '关闭'}过滤`)
+ return msg
+ }
+
+ /**
+ * @description: vilipix随机图片
+ * @return {Array}
+ */
+ async vilipixRandomImg (limit) {
+ let api = `https://www.vilipix.com/api/v1/picture/recommand?limit=${limit}&offset=${_.random(1, 700)}`
+ let res = await request.get(api).then(res => res.json())
+ if (!res.data || !res.data.rows) throw Error('呜呜呜,没拿到瑟瑟的图片(˃ ⌑ ˂ഃ )')
+ return res.data.rows.map(item => {
+ let { picture_id, title, regular_url, tags, like_total } = item
+ return [
+ `标题:${title}\n`,
+ `点赞: ${like_total}\n`,
+ `插画ID:${picture_id}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ segment.image(regular_url)
+ ]
+ })
+ }
+
+ /**
+ * @description: 相关作品
+ * @param {String} pid
+ * @return {*}
+ */
+ async relatedIllust (pid, isfilter = true) {
+ let params = { id: pid }
+ let res = null
+ if (this.PixivClient.auth) {
+ res = await this.PixivClient.related(params)
+ } else {
+ res = await request.get(`${this.domain}/related`, { params }).then(res => res.json())
+ }
+ if (res.error) throw Error(res.error.user_message)
+ if (_.isEmpty(res.illusts)) throw Error('呃...没有数据(•ิ_•ิ)')
+
+ let illusts = []
+ let filter = 0
+ for (let i of res.illusts) {
+ let { id, title, user, tags, total_bookmarks, image_urls, x_restrict } = await this._format(i)
+ if (isfilter && x_restrict) {
+ filter++
+ continue
+ }
+ illusts.push([
+ `标题:${title}\n`,
+ `画师:${user.name}\n`,
+ `PID:${id}\n`,
+ `UID:${user.id}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `Tag:${_.truncate(tags)}\n`,
+ await this._requestPixivImg(image_urls.large)
+ ])
+ }
+ if (_.isEmpty(illusts)) throw Error('啊啊啊!!!居然全是瑟瑟哒不给你看(*/ω\*)')
+
+ return [
+ `Pid:${pid}的相关作品,共${res.illusts.length}张${filter ? `,过滤${filter}张` : ''}`,
+ ...illusts
+ ]
+ }
+
+ /** p站单图 */
+ async pximg (pro) {
+ let url = 'https://image.anosu.top/pixiv/json'
+ const params = {
+ r18: pro ? 1 : 0,
+ proxy: this.proxy
+ }
+ let res = await request.get(url, {
+ statusCode: 'json',
+ params
+ })
+ let { pid, uid, title, user, tags, url: urls, r18 } = res[0]
+ let msg = [
+ `Pid: ${pid}\n`,
+ `Uid: ${uid}\n`,
+ `R18: ${r18 ?? false}\n`,
+ `标题:${title}\n`,
+ `画师:${user}\n`,
+ `Tag:${tags.join(',')}\n`,
+ await this._requestPixivImg(urls)
+ ]
+ return msg
+ }
+
+ /**
+ * @description: 推荐作品
+ * @param {Number} num 数量
+ * @return {Promise}
+ */
+ async illustRecommended (num) {
+ let list = await this.PixivClient.illustRecommended()
+ return Promise.all(_.take(list.illusts, num).map(async (item) => {
+ let { id, title, user, tags, total_bookmarks, image_urls } = this._format(item)
+ return [
+ `标题:${title}\n`,
+ `画师:${user.name}\n`,
+ `PID:${id}\n`,
+ `UID:${user.id}\n`,
+ `点赞:${total_bookmarks}\n`,
+ `Tag:${_.truncate(tags)}`,
+ await this._requestPixivImg(image_urls.large)
+ ]
+ }))
+ }
+
+ /**
+ * @description: 请求p站图片
+ * @param {String} url
+ * @return {Promise}
+ */
+ async _requestPixivImg (url) {
+ url = url.replace('i.pximg.net', this.proxy)
+ logger.debug(`pixiv getImg URL: ${url}`)
+ let headers = /s.pximg.net/.test(url) ? undefined : this.headers
+ return request.proxyRequestImg(url, { headers })
+ }
+
+ /**
+ * @description: 格式化
+ * @param {Object} illusts 处format理对象
+ * @return {Object}
+ * title 标题
+ * id pid
+ * total_bookmarks 点赞
+ * total_view 访问量
+ * tags 标签
+ * url 图片链接
+ * user 作者信息
+ * image_urls 单张图片
+ * x_restrict 是否为全年龄
+ * create_date 发布时间
+ * illust_ai_type 是否为AI作品
+ * visible 是否为可见作品
+ */
+ _format (illusts) {
+ let url = []
+ let { tags, meta_single_page, meta_pages } = illusts
+ tags = _.uniq(_.compact(_.flattenDeep(tags?.map(item => Object.values(item)))))
+ if (!_.isEmpty(meta_single_page)) {
+ url.push(meta_single_page.original_image_url)
+ } else {
+ url = meta_pages.map(item => item.image_urls.original)
+ }
+ return { ...illusts, tags, url }
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/model/Pixiv/api.js b/Yunzai/plugins/yenai-plugin/model/Pixiv/api.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8d9c33cf0dbcc15b16c51b146cf5e8cfdf1f356
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/Pixiv/api.js
@@ -0,0 +1,239 @@
+import request, { qs } from '../../lib/request/request.js'
+import moment from 'moment'
+import { Config } from '../../components/index.js'
+import md5 from 'md5'
+
+const CLIENT_ID = 'MOBrBDS8blbauoSck0ZfDbtuzpyT'
+const CLIENT_SECRET = 'lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj'
+const HASH_SECRET = '28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c'
+export default class PixivApi {
+ constructor (refresh_token) {
+ this.baseUrl = 'https://app-api.pixiv.net/'
+ this.headers = {
+ 'User-Agent': 'PixivIOSApp/7.13.3 (iOS 14.6; iPhone13,2)',
+ 'Accept-Language': Config.pixiv.language,
+ 'App-OS': 'ios',
+ 'App-OS-Version': '14.6',
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Accept': '*/*',
+ 'Connection': 'Keep-Alive'
+ }
+ this._once = false
+ this.refresh_token = refresh_token
+ this.access_token = null
+ this.auth = null
+ }
+
+ async login () {
+ if (!this.refresh_token) {
+ throw Error('[Yenai][Pixiv] 未配置refresh_token刷新令牌')
+ }
+ const local_time = moment().format()
+ const headers = {
+ ...this.headers,
+ 'X-Client-Time': local_time,
+ 'X-Client-Hash': md5(`${local_time}${HASH_SECRET}`)
+ }
+ const data = {
+ client_id: CLIENT_ID,
+ client_secret: CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.refresh_token
+ }
+ const { response, error } = await request.post('https://oauth.secure.pixiv.net/auth/token', {
+ data,
+ headers
+ }).then(res => res.json())
+ if (error) throw Error(`[Yenai][Pixiv]login Error Response: ${error}`)
+ this.access_token = response.access_token
+ this.refresh_token = response.refresh_token
+ this.auth = response
+ if (this.access_token) {
+ const { id, name, account } = this.auth.user
+ logger.info(`[Yenai][Pixiv]login ${logger.yellow(`${name}(${id}) @${account}`)} ${logger.green('success')}`)
+ } else {
+ logger.error(`[Yenai][Pixiv]login ${logger.red('fail')}`)
+ }
+ }
+
+ async request (target, options = {}, caching = false) {
+ if (!this.auth) await this.login()
+ try {
+ return await this._get(target, options, caching)
+ } catch (error) {
+ if (this._once) {
+ this._once = false
+ throw error
+ }
+ await this.login()
+ this._once = true
+ return await this._get(target, options, caching)
+ }
+ }
+
+ async _get (target, options = {}, cache) {
+ const headers = {
+ ...this.headers,
+ Authorization: `Bearer ${this.access_token}`
+ }
+ // 读取缓存
+ const cacheUrl = options.params ? target + '?' + qs(options.params) : target
+ const cacheKey = `yenai:pixiv:cache:${cacheUrl}`
+ const cacheData = await redis.get(cacheKey)
+ if (cacheData) return JSON.parse(cacheData)
+ // 请求
+ let data = await request[options.data ? 'post' : 'get'](this.baseUrl + target, {
+ headers,
+ ...options,
+ statusCode: 'json'
+ })
+ // 写入缓存
+ if (cache) {
+ redis.set(cacheKey, JSON.stringify(data), {
+ EX: timeToSeconds(cache)
+ })
+ }
+ return data
+ }
+
+ async tags () {
+ return this.request('v1/trending-tags/illust')
+ }
+
+ async rank ({
+ mode = 'week',
+ date = moment().subtract(moment().utcOffset(9).hour() >= 12 ? 1 : 2, 'days').format('YYYY-MM-DD'),
+ page = 1,
+ size = 30
+ }) {
+ return this.request('v1/illust/ranking', {
+ params: {
+ mode,
+ date,
+ offset: (page - 1) * size
+ }
+ }, getNoonTomorrow())
+ }
+
+ async illust ({ id }) {
+ return this.request('v1/illust/detail', {
+ params: {
+ illust_id: id
+ }
+ })
+ }
+
+ async member ({ id }) {
+ return this.request('v1/user/detail', {
+ params: {
+ illust_id: id
+ }
+ })
+ }
+
+ async member_illust ({
+ id,
+ page = 1,
+ size = 30,
+ illust_type = 'illust'
+ }) {
+ return this.request('v1/user/illusts', {
+ params: {
+ user_id: id,
+ type: illust_type,
+ offset: (page - 1) * size
+ }
+ })
+ }
+
+ async search ({
+ word,
+ page = 1,
+ size = 30,
+ order = 'date_desc',
+ mode = 'partial_match_for_tags',
+ include_translated_tag_results = true
+ }) {
+ return this.request('v1/search/illust', {
+ params: {
+ word,
+ search_target: mode,
+ sort: order,
+ offset: (page - 1) * size,
+ include_translated_tag_results
+ }
+ })
+ }
+
+ async search_user ({
+ word,
+ page = 1,
+ size = 30
+ }) {
+ return await this.request(
+ 'v1/search/user',
+ {
+ params: {
+ word,
+ offset: (page - 1) * size
+ }
+ }
+ )
+ }
+
+ async related ({
+ id,
+ page = 1,
+ size = 30
+ }) {
+ return await this.request(
+ 'v2/illust/related',
+ {
+ params: {
+ illust_id: id,
+ offset: (page - 1) * size
+ }
+ }
+ )
+ }
+
+ async illustRecommended (params = {}) {
+ return await this.request('v1/illust/recommended', params)
+ }
+}
+function timeToSeconds (time) {
+ let seconds = 0
+ let timeArray = time.split(' ')
+ for (let i = 0; i < timeArray.length; i++) {
+ let unit = timeArray[i].charAt(timeArray[i].length - 1)
+ let value = parseInt(timeArray[i].substring(0, timeArray[i].length - 1))
+ switch (unit) {
+ case 's':
+ seconds += value
+ break
+ case 'm':
+ seconds += value * 60
+ break
+ case 'h':
+ seconds += value * 60 * 60
+ break
+ case 'd':
+ seconds += value * 60 * 60 * 24
+ break
+ default:
+ break
+ }
+ }
+ return seconds
+}
+
+function getNoonTomorrow () {
+ const now = moment() // 获取当前时间
+ const noonToday = moment().startOf('day').add(12, 'hours') // 获取今天中午12点的时间
+ const noonTomorrow = moment().add(1, 'day').startOf('day').add(12, 'hours') // 获取明天中午12点的时间
+ let time = now < noonToday
+ ? noonToday.diff(now, 'hours')
+ : noonTomorrow.diff(now, 'hours')
+ if (time > 12) time = 12
+ return time + 'h'
+}
diff --git a/Yunzai/plugins/yenai-plugin/model/State.js b/Yunzai/plugins/yenai-plugin/model/State.js
new file mode 100644
index 0000000000000000000000000000000000000000..413c57cdee789bc01dc204b172dcbb7d01289cab
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/State.js
@@ -0,0 +1,475 @@
+import os from 'os'
+import _ from 'lodash'
+import fs from 'fs'
+import { common } from './index.js'
+import { Config, Data } from '../components/index.js'
+import request from '../lib/request/request.js'
+
+export default new class {
+ constructor () {
+ this.si = null
+ this.osInfo = null
+ // 是否可以获取gpu
+ this.isGPU = false
+ // 网络
+ this._network = null
+ // 读写速率
+ this._fsStats = null
+ // 记录60条数据一分钟记录一次
+ this.chartData = {
+ network: {
+ // 上行
+ upload: [],
+ // 下行
+ download: []
+ },
+ fsStats: {
+ // 读
+ readSpeed: [],
+ // 写
+ writeSpeed: []
+ },
+ // cpu
+ cpu: [],
+ // 内存
+ ram: [],
+ // 主题
+ echarts_theme: Data.readJSON('resources/state/theme_westeros.json')
+ }
+
+ this.valueObject = {
+ networkStats: 'rx_sec,tx_sec,iface',
+ currentLoad: 'currentLoad',
+ mem: 'active',
+ fsStats: 'wx_sec,rx_sec'
+ }
+
+ this.init()
+ }
+
+ set network (value) {
+ if (_.isNumber(value[0]?.tx_sec) && _.isNumber(value[0]?.rx_sec)) {
+ this._network = value
+ this.addData(this.chartData.network.upload, [Date.now(), value[0].tx_sec])
+ this.addData(this.chartData.network.download, [Date.now(), value[0].rx_sec])
+ }
+ }
+
+ get network () {
+ return this._network
+ }
+
+ set fsStats (value) {
+ if (_.isNumber(value?.wx_sec) && _.isNumber(value?.rx_sec)) {
+ this._fsStats = value
+ this.addData(this.chartData.fsStats.writeSpeed, [Date.now(), value.wx_sec])
+ this.addData(this.chartData.fsStats.readSpeed, [Date.now(), value.rx_sec])
+ }
+ }
+
+ get fsStats () {
+ return this._fsStats
+ }
+
+ async initDependence () {
+ try {
+ this.si = await import('systeminformation')
+ this.osInfo = await this.si.osInfo()
+ return this.si
+ } catch (error) {
+ if (error.stack?.includes('Cannot find package')) {
+ logger.warn('--------椰奶依赖缺失--------')
+ logger.warn(`yenai-plugin 缺少依赖将无法使用 ${logger.yellow('椰奶状态')}`)
+ logger.warn(`如需使用请运行:${logger.red('pnpm add systeminformation -w')}`)
+ logger.warn('---------------------------')
+ logger.debug(decodeURI(error.stack))
+ } else {
+ logger.error(`椰奶载入依赖错误:${logger.red('systeminformation')}`)
+ logger.error(decodeURI(error.stack))
+ }
+ }
+ }
+
+ async init () {
+ if (!await this.initDependence()) return
+ const { controllers } = await this.si.graphics()
+ // 初始化GPU获取
+ if (controllers?.find(item =>
+ item.memoryUsed && item.memoryFree && item.utilizationGpu)
+ ) {
+ this.isGPU = true
+ }
+ // 给有问题的用户关闭定时器
+ if (!Config.state.statusTask) return
+
+ if (Config.state.statusPowerShellStart) this.si.powerShellStart()
+ this.getData()
+ // 网速
+ const Timer = setInterval(async () => {
+ let data = await this.getData()
+ if (_.isEmpty(data)) clearInterval(Timer)
+ }, 60000)
+ }
+
+ async getData () {
+ let data = await this.si.get(this.valueObject)
+ _.forIn(data, (value, key) => {
+ if (_.isEmpty(value)) {
+ logger.debug(`获取${key}数据失败,停止获取对应数据`)
+ delete this.valueObject[key]
+ }
+ })
+ let {
+ fsStats,
+ networkStats,
+ mem: { active },
+ currentLoad: { currentLoad }
+ } = data
+ this.fsStats = fsStats
+ this.network = networkStats
+ if (_.isNumber(active)) {
+ this.addData(this.chartData.ram, [Date.now(), active])
+ }
+ if (_.isNumber(currentLoad)) {
+ this.addData(this.chartData.cpu, [Date.now(), currentLoad])
+ }
+ return data
+ }
+
+ /**
+ * 向数组中添加数据,如果数组长度超过允许的最大值,则删除最早添加的数据
+ *
+ * @param {Array} arr - 要添加数据的数组
+ * @param {*} data - 要添加的新数据
+ * @param {number} [maxLen=60] - 数组允许的最大长度,默认值为60
+ * @returns {void}
+ */
+ addData (arr, data, maxLen = 60) {
+ if (data === null || data === undefined) return
+ // 如果数组长度超过允许的最大值,删除第一个元素
+ if (arr.length >= maxLen) {
+ _.pullAt(arr, 0)
+ }
+ // 添加新数据
+ arr.push(data)
+ }
+
+ /**
+ * 重试获取数据,直到成功或达到最大重试次数。
+ * @param {Function} fetchFunc 获取数据的函数,返回一个Promise对象。
+ * @param {Array} [params=[]] 需要执行函数的参数数组
+ * @param {Number} [timerId] 定时器的id,用于在获取数据失败时停止定时器
+ * @param {Number} [maxRetryCount=3] 最大重试次数。
+ * @param {Number} [retryInterval=1000] 两次重试之间的等待时间,单位为毫秒。。
+ * @return {Promise} 获取到的数据。如果达到最大重试次数且获取失败,则返回null。
+ */
+ async fetchDataWithRetry (fetchFunc, params = [], timerId, maxRetryCount = 3, retryInterval = 1000) {
+ let retryCount = 0
+ let data = null
+ while (retryCount <= maxRetryCount) {
+ data = await fetchFunc(...params)
+ if (!_.isEmpty(data)) {
+ break
+ }
+ retryCount++
+ if (retryCount > maxRetryCount && timerId) {
+ logger.debug(`获取${fetchFunc.name}数据失败,停止定时器`)
+ clearInterval(timerId)
+ break
+ }
+ await new Promise(resolve => setTimeout(resolve, retryInterval))
+ }
+ return data
+ }
+
+ /**
+ * 将文件大小从字节转化为可读性更好的格式,例如B、KB、MB、GB、TB。
+ *
+ * @param {number} size - 带转化的字节数。
+ * @param {boolean} [isByte=true] - 如果为 true,则最终的文件大小显示保留 B 的后缀.
+ * @param {boolean} [isSuffix=true] - 如果为 true,则在所得到的大小后面加上 kb、mb、gb、tb 等后缀.
+ * @returns {string} 文件大小格式转换后的字符串.
+ */
+ getFileSize (size, isByte = true, isSuffix = true) { // 把字节转换成正常文件大小
+ if (size == null || size == undefined) return 0
+ let num = 1024.00 // byte
+ if (isByte && size < num) {
+ return size.toFixed(2) + 'B'
+ }
+ if (size < Math.pow(num, 2)) {
+ return (size / num).toFixed(2) + `K${isSuffix ? 'b' : ''}`
+ } // kb
+ if (size < Math.pow(num, 3)) {
+ return (size / Math.pow(num, 2)).toFixed(2) + `M${isSuffix ? 'b' : ''}`
+ } // M
+ if (size < Math.pow(num, 4)) {
+ return (size / Math.pow(num, 3)).toFixed(2) + 'G'
+ } // G
+ return (size / Math.pow(num, 4)).toFixed(2) + 'T' // T
+ }
+
+ /**
+ * @description: 圆形进度条渲染
+ * @param {Number} res 百分比小数
+ * @return {*} css样式
+ */
+ Circle (res) {
+ let num = (res * 360).toFixed(0)
+ let color = 'var(--low-color)'
+ if (res >= 0.9) {
+ color = 'var(--high-color)'
+ } else if (res >= 0.8) {
+ color = 'var(--medium-color)'
+ }
+ let leftCircle = `style="transform:rotate(-180deg);background:${color};"`
+ let rightCircle = `style="transform:rotate(360deg);background:${color};"`
+ if (num > 180) {
+ leftCircle = `style="transform:rotate(${num}deg);background:${color};"`
+ } else {
+ rightCircle = `style="transform:rotate(-${180 - num}deg);background:${color};"`
+ }
+ return { leftCircle, rightCircle }
+ }
+
+ /** 获取nodejs内存情况 */
+ getNodeInfo () {
+ let memory = process.memoryUsage()
+ // 总共
+ let rss = this.getFileSize(memory.rss)
+ // 堆
+ let heapTotal = this.getFileSize(memory.heapTotal)
+ // 栈
+ let heapUsed = this.getFileSize(memory.heapUsed)
+ // 占用率
+ let occupy = (memory.rss / (os.totalmem() - os.freemem())).toFixed(2)
+ return {
+ ...this.Circle(occupy),
+ inner: Math.round(occupy * 100) + '%',
+ title: 'Node',
+ info: [
+ `总 ${rss}`,
+ `堆 ${heapTotal}`,
+ `栈 ${heapUsed}`
+ ]
+ }
+ }
+
+ /** 获取当前内存占用 */
+ getMemUsage () {
+ // 内存使用率
+ let MemUsage = (1 - os.freemem() / os.totalmem()).toFixed(2)
+ // 空闲内存
+ let freemem = this.getFileSize(os.freemem())
+ // 总共内存
+ let totalmem = this.getFileSize(os.totalmem())
+ // 使用内存
+ let Usingmemory = this.getFileSize((os.totalmem() - os.freemem()))
+
+ return {
+ ...this.Circle(MemUsage),
+ inner: Math.round(MemUsage * 100) + '%',
+ title: 'RAM',
+ info: [
+ `总共 ${totalmem}`,
+ `已用 ${Usingmemory}`,
+ `空闲 ${freemem}`
+ ]
+ }
+ }
+
+ /** 获取CPU占用 */
+ async getCpuInfo () {
+ let { currentLoad: { currentLoad }, cpuCurrentSpeed } = await this.si.get({
+ currentLoad: 'currentLoad',
+ cpuCurrentSpeed: 'max,avg'
+ })
+ if (currentLoad == null || currentLoad == undefined) return false
+ // 核心
+ let cores = os.cpus()
+ // cpu制造者
+ let cpuModel = cores[0]?.model.slice(0, cores[0]?.model.indexOf(' ')) || ''
+ return {
+ ...this.Circle(currentLoad / 100),
+ inner: Math.round(currentLoad) + '%',
+ title: 'CPU',
+ info: [
+ `${cpuModel} ${cores.length}核 ${this.osInfo?.arch}`,
+ `平均${cpuCurrentSpeed.avg}GHz`,
+ `最大${cpuCurrentSpeed.max}GHz`
+ ]
+
+ }
+ }
+
+ /** 获取GPU占用 */
+ async getGPU () {
+ if (!this.isGPU) return false
+ try {
+ const { controllers } = await this.si.graphics()
+ let graphics = controllers?.find(item =>
+ item.memoryUsed && item.memoryFree && item.utilizationGpu
+ )
+ if (!graphics) {
+ logger.warn('[Yenai-plugin][state]状态GPU数据异常:\n', controllers)
+ return false
+ }
+ let {
+ vendor, temperatureGpu, utilizationGpu,
+ memoryTotal, memoryUsed, powerDraw
+ } = graphics
+ temperatureGpu && (temperatureGpu = temperatureGpu + '℃')
+ powerDraw && (powerDraw = powerDraw + 'W')
+ return {
+ ...this.Circle(utilizationGpu / 100),
+ inner: Math.round(utilizationGpu) + '%',
+ title: 'GPU',
+ info: [
+ `${vendor} ${temperatureGpu} ${powerDraw}`,
+ `总共 ${(memoryTotal / 1024).toFixed(2)}G`,
+ `已用 ${(memoryUsed / 1024).toFixed(2)}G`
+ ]
+ }
+ } catch (e) {
+ logger.warn('[Yenai-Plugin][State] 获取GPU失败')
+ return false
+ }
+ }
+
+ /**
+ * @description: 获取硬盘
+ * @return {*}
+ */
+ async getFsSize () {
+ // 去重
+ let HardDisk = _.uniqWith(await this.si.fsSize(),
+ (a, b) =>
+ a.used === b.used && a.size === b.size && a.use === b.use && a.available === b.available
+ )
+ .filter(item => item.size && item.used && item.available && item.use)
+ // 为空返回false
+ if (_.isEmpty(HardDisk)) return false
+ // 数值转换
+ return HardDisk.map(item => {
+ item.used = this.getFileSize(item.used)
+ item.size = this.getFileSize(item.size)
+ item.use = Math.round(item.use)
+ item.color = 'var(--low-color)'
+ if (item.use >= 90) {
+ item.color = 'var(--high-color)'
+ } else if (item.use >= 70) {
+ item.color = 'var(--medium-color)'
+ }
+ return item
+ })
+ }
+
+ /** 获取FastFetch */
+ async getFastFetch (e) {
+ if (process.platform == 'win32' && !/pro/.test(e.msg)) return ''
+ let ret = await common.execSync('bash plugins/yenai-plugin/resources/state/state.sh')
+ if (ret.error) {
+ e.reply(`❎ 请检查是否使用git bash启动Yunzai-bot\n错误信息:${ret.stderr}`)
+ return ''
+ }
+ return ret.stdout.trim()
+ }
+
+ // 获取读取速率
+ get DiskSpeed () {
+ if (!this.fsStats ||
+ this.fsStats.rx_sec == null ||
+ this.fsStats.wx_sec == null
+ ) {
+ return false
+ }
+ return {
+ rx_sec: this.getFileSize(this.fsStats.rx_sec, false, false),
+ wx_sec: this.getFileSize(this.fsStats.wx_sec, false, false)
+ }
+ }
+
+ /**
+ * @description: 获取网速
+ * @return {object}
+ */
+ get getnetwork () {
+ let network = _.cloneDeep(this.network)?.[0]
+ if (!network || network.rx_sec == null || network.tx_sec == null) {
+ return false
+ }
+ network.rx_sec = this.getFileSize(network.rx_sec, false, false)
+ network.tx_sec = this.getFileSize(network.tx_sec, false, false)
+ // return network
+ return {
+ first: network.iface,
+ tail: `↑${network.tx_sec}/s | ↓${network.rx_sec}/s`
+ }
+ }
+
+ /**
+ * @description: 取插件包
+ * @return {*} 插件包数量
+ */
+ get getPluginNum () {
+ let str = './plugins'
+ let arr = fs.readdirSync(str)
+ let plugin = []
+ arr.forEach((val) => {
+ let ph = fs.statSync(str + '/' + val)
+ if (ph.isDirectory()) {
+ plugin.push(val)
+ }
+ })
+ let del = ['example', 'genshin', 'other', 'system', 'bin']
+ plugin = plugin.filter(item => !del.includes(item))
+ const plugins = plugin?.length || 0
+ const js = fs.readdirSync('./plugins/example')?.filter(item => item.includes('.js'))?.length || 0
+ // return {
+ // plugins: plugin?.length || 0,
+ // js: fs.readdirSync('./plugins/example')?.filter(item => item.includes('.js'))?.length || 0
+ // }
+ return {
+ first: '插件',
+ tail: `${plugins} plugin | ${js} js`
+ }
+ }
+
+ async getNetworkLatency (url, timeoutTime = 5000) {
+ const AbortController = globalThis.AbortController || await import('abort-controller')
+
+ const controller = new AbortController()
+ const timeout = setTimeout(() => {
+ controller.abort()
+ }, timeoutTime)
+ try {
+ const startTime = Date.now()
+ let { status } = await request.get(url, { signal: controller.signal })
+ const endTime = Date.now()
+ let delay = endTime - startTime
+ let color = ''; let statusColor = ''
+ if (delay > 2000) {
+ color = '#F44336'
+ } else if (delay > 500) {
+ color = '#d68100'
+ } else {
+ color = '#188038'
+ }
+ if (status >= 500) {
+ statusColor = '#9C27B0'
+ } else if (status >= 400) {
+ statusColor = '#F44336'
+ } else if (status >= 300) {
+ statusColor = '#FF9800'
+ } else if (status >= 200) {
+ statusColor = '#188038'
+ } else if (status >= 100) {
+ statusColor = '#03A9F4'
+ }
+ return `${status} | ${delay}ms`
+ } catch {
+ return "timeout"
+ } finally {
+ clearTimeout(timeout)
+ }
+ }
+}()
diff --git a/Yunzai/plugins/yenai-plugin/model/api/QQApi.js b/Yunzai/plugins/yenai-plugin/model/api/QQApi.js
new file mode 100644
index 0000000000000000000000000000000000000000..aace7252116604f7ed75fadda484b57e8e85f77d
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/model/api/QQApi.js
@@ -0,0 +1,550 @@
+import fetch from 'node-fetch'
+import { common } from '../index.js'
+import _ from 'lodash'
+import moment from 'moment'
+import request from '../../lib/request/request.js'
+/** QQ接口 */
+export default class {
+ constructor (e) {
+ this.e = e
+ this.Bot = e.bot ?? Bot
+ this.headers = {
+ 'Content-type': 'application/json;charset=UTF-8',
+ 'Cookie': this.Bot?.cookies?.['qun.qq.com'],
+ 'qname-service': '976321:131072',
+ 'qname-space': 'Production'
+ }
+ }
+
+ getGtk (data) {
+ let ck = common.getck(data, this.Bot)
+ // eslint-disable-next-line no-var
+ for (var e = ck.p_skey || '', n = 5381, r = 0, o = e.length; r < o; ++r) {
+ n += (n << 5) + e.charAt(r).charCodeAt(0)
+ }
+ return 2147483647 & n
+ }
+
+ /**
+ * @description: 取说说列表
+ * @param {*} e oicq
+ * @param {Number} num 数量
+ * @param {Number} pos 偏移量
+ * @return {Object} QQ空间数据
+ */
+ async getQzone (num = 20, pos = 0) {
+ let url = `https://user.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6?uin=${this.Bot.uin}&ftype=0&sort=0&pos=${pos}&num=${num}&replynum=100&g_tk=${this.Bot.bkn}&code_version=1&format=json&need_private_comment=1`
+ return await fetch(url, {
+ headers: {
+ Cookie: this.Bot.cookies['qzone.qq.com']
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ }
+
+ /**
+ * @description: 删除说说
+ * @param {String} tid tid参数
+ * @param {String} t1_source t1_source参数
+ */
+ async delQzone (tid, t1_source) {
+ let url = `https://user.qzone.qq.com/proxy/domain/taotao.qzone.qq.com/cgi-bin/emotion_cgi_delete_v6?&g_tk=${this.Bot.bkn}`
+ // 发送请求
+ return await fetch(url, {
+ method: 'POST',
+ body: `hostuin=${this.Bot.uin}&tid=${tid}&t1_source=${t1_source}&code_version=1&format=json`,
+ headers: {
+ Cookie: this.Bot.cookies['qzone.qq.com']
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ }
+
+ /** 删除全部说说 */
+ async delQzoneAll () {
+ let ck = common.getck('qzone.qq.com', this.Bot)
+ return await fetch(`http://xiaobai.klizi.cn/API/qqgn/ss_empty.php?data=&uin=${this.Bot.uin}&skey=${ck.skey}&pskey=${ck.p_skey}`).then(res => res.text()).catch(err => logger.error(err))
+ // let num = 0
+ // while (true) {
+ // let list = await this.getQzone(40)
+ // if (list.total == 0) return num == 0 ? '❎ 说说列表空空' : '✅ 已清空全部说说'
+ // for (let item of list.msglist) {
+ // let res = await this.delQzone(item.tid, item.t1_source)
+ // if (res.code != 0) return `❎ 遇到错误 ${JSON.stringify(res)}`
+ // }
+ // num++
+ // }
+ }
+
+ /** 发送说说 */
+ async setQzone (con, img) {
+ let ck = common.getck('qzone.qq.com', this.Bot)
+
+ if (img) {
+ let url = `http://xiaobai.klizi.cn/API/qqgn/ss_sendimg.php?uin=${this.Bot.uin}&skey=${ck.skey}&pskey=${ck.p_skey}&url=${img[0]}&msg=${con}`
+ return await fetch(url).then(res => res.json()).catch(err => logger.error(err))
+ } else {
+ let url = `https://user.qzone.qq.com/proxy/domain/taotao.qzone.qq.com/cgi-bin/emotion_cgi_publish_v6?&g_tk=${this.Bot.bkn}`
+ return await fetch(url, {
+ method: 'POST',
+ body: `syn_tweet_verson=1¶mstr=1&con=${con}&feedversion=1&ver=1&ugc_right=1&to_sign=1&hostuin=${this.Bot.uin}&code_version=1&format=json`,
+ headers: {
+ Cookie: this.Bot.cookies['qzone.qq.com']
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ }
+ }
+
+ /**
+ * @description: 获取留言
+ * @param {Number} num 数量为0时返回为全部
+ * @param {Number} start 偏移量/开始的位置
+ * @return {*}
+ */
+ async getQzoneMsgb (num = 0, start = 0) {
+ let url = `https://user.qzone.qq.com/proxy/domain/m.qzone.qq.com/cgi-bin/new/get_msgb?uin=${this.Bot.uin}&hostUin=${this.Bot.uin}&start=${start}&s=0.45779069937151884&format=json&num=${num}&inCharset=utf-8&outCharset=utf-8&g_tk=${this.Bot.bkn}`
+ return await fetch(url, {
+ headers: {
+ cookie: this.Bot.cookies['qzone.qq.com']
+ }
+ }).then(res => res.json())
+ }
+
+ /**
+ * @description: 删除留言
+ * @param {*} id 留言id
+ * @param {*} uinId
+ * @return {*}
+ */
+ async delQzoneMsgb (id, uinId) {
+ let delurl = `https://h5.qzone.qq.com/proxy/domain/m.qzone.qq.com/cgi-bin/new/del_msgb?&g_tk=${this.Bot.bkn}`
+ return await fetch(delurl, {
+ method: 'POST',
+ headers: {
+ Cookie: this.Bot.cookies['qzone.qq.com']
+ },
+ body: `hostUin=${this.Bot.uin}&idList=${id}&uinList=${uinId}&format=json&iNotice=1&inCharset=utf-8&outCharset=utf-8&ref=qzone&json=1&g_tk=${this.Bot.bkn}`
+ }).then(res => res.json())
+ }
+
+ /** 删除全部留言 */
+ async delQzoneMsgbAll () {
+ let ck = common.getck('qzone.qq.com', this.Bot)
+ return await fetch(`http://xiaobai.klizi.cn/API/qqgn/qzone_emptymsgb.php?data=&uin=${this.Bot.uin}&skey=${ck.skey}&pskey=${ck.p_skey}`).then(res => res.text()).catch(err => logger.error(err))
+ // let num = 0
+ // while (true) {
+ // let list = await this.getQzoneMsgb(40)
+ // if (list.code != 0) return `❎ 获取列表错误 ${JSON.stringify(list)}`
+ // if (list.data.total == 0) return num == 0 ? '❎ 留言列表空空' : '✅ 已清空全部留言'
+ // for (let item of list.data.commentList) {
+ // let res = await this.delQzoneMsgb(item.id, item.uin)
+ // if (res.code != 0) return `❎ 遇到错误 ${JSON.stringify(res)}`
+ // }
+ // num++
+ // }
+ }
+
+ // ----------------------------------------------------公告---------------------------------------------
+ /**
+ * @description: 获取群公告
+ * @param {String} group 群号
+ * @param {String} item 序号
+ * @return {Object}
+ */
+ async getAnnouncelist (group_id, s = 0) {
+ let n = s ? 1 : 20
+ let url = `https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=${this.Bot.bkn}&qid=${group_id}&ft=23&s=${s - 1}&n=${n}`
+ let res = await fetch(url, { headers: { Cookie: this.Bot.cookies['qun.qq.com'] } }).then(res => res.json()).catch(err => logger.error(err))
+ if (!res) return false
+ if (s) {
+ return {
+ text: res.feeds[0].msg.text,
+ fid: res.feeds[0].fid
+ }
+ } else {
+ return res.feeds.map((item, index) => `${index + 1}、${_.truncate(item.msg.text)}`).join('\n')
+ }
+ }
+
+ /**
+ * @description: 发送群公告
+ * @param {Number} group_id 发送群号
+ * @param {String} msg 发送内容
+ */
+ async setAnnounce (group_id, msg) {
+ let url = `https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${this.Bot.bkn}`
+ return await fetch(url, {
+ method: 'POST',
+ body: `qid=${group_id}&bkn=${this.Bot.bkn}&text=${msg}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}`,
+ headers: {
+ Cookie: this.Bot.cookies['qun.qq.com']
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ }
+
+ /**
+ * @description: 删群公告
+ * @param {Number} group_id 群号
+ * @param {Number} num 序号
+ */
+ async delAnnounce (group_id, num) {
+ let fid = await this.getAnnouncelist(group_id, num)
+ if (!fid) return false
+
+ let url = `https://web.qun.qq.com/cgi-bin/announce/del_feed?bkn=${this.Bot.bkn}`
+ let res = await fetch(url, {
+ method: 'POST',
+ body: `bkn=${this.Bot.bkn}&fid=${fid.fid}&qid=${group_id}`,
+ headers: {
+ Cookie: this.Bot.cookies['qun.qq.com']
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ return {
+ ...res,
+ text: _.truncate(fid.text)
+ }
+ }
+
+ /** 群星级 */
+ async getCreditLevelInfo (group_id) {
+ let url = `https://qqweb.qq.com/c/activedata/get_credit_level_info?bkn=${this.Bot.bkn}&uin=${this.Bot.uin}&gc=${group_id}`
+ return await fetch(url, {
+ headers: {
+ 'Cookie': this.Bot.cookies['qqweb.qq.com'],
+ 'Referer': `https://qqweb.qq.com/m/business/qunlevel/index.html?gc=${group_id}&from=0&_wv=1027`,
+ 'User-agent': 'Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/046141 Mobile Safari/537.36 V1_AND_SQ_8.3.9_350_TIM_D QQ/3.5.0.3148 NetType/WIFI WebP/0.3.0 Pixel/1080 StatusBarHeight/81 SimpleUISwitch/0 QQTheme/1015712'
+ }
+ }).then(res => res.json()).catch(err => logger.error(err))
+ }
+
+ /** 查看本群龙王 */
+ async dragon (group_id) {
+ let url = `https://qun.qq.com/interactive/honorlist?gc=${group_id}&type=1&_wv=3&_wwv=129`
+ let res = await fetch(url, { headers: { Cookie: this.Bot.cookies['qun.qq.com'] } })
+ .then(res => res.text()).catch(err => logger.error(err))
+ let data = res.match(/
+{{/block}}
+{{block 'main'}}
+
+
+
+
+
+
+
+{{/block}}
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/resources/state/state.css b/Yunzai/plugins/yenai-plugin/resources/state/state.css
new file mode 100644
index 0000000000000000000000000000000000000000..3607085b8f82ccb77d9767d63ae841fa95bb5ab4
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/resources/state/state.css
@@ -0,0 +1,233 @@
+.speed p, .HardDisk_li .mount, .header h1 {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+:root {
+ --high-color: #d73403;
+ --medium-color: #ffa500;
+ --low-color: #90ee90;
+}
+
+.container {
+ background-color: white;
+ background-position: center top;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+li {
+ list-style: none;
+}
+
+body {
+ display: flex;
+ height: 100%;
+ flex-direction: column;
+ justify-content: space-around;
+}
+
+.box {
+ margin: 20px;
+ padding: 10px;
+ background: rgba(255, 255, 255, 0.45);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ -webkit-backdrop-filter: blur(10px);
+ backdrop-filter: blur(10px);
+ border-radius: 10px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ font-weight: 700;
+}
+
+.tb {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+}
+.tb .avatar {
+ position: relative;
+ height: 100px;
+ width: 100px;
+ border-radius: 50%;
+ margin: 0 20px;
+ flex-shrink: 0;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+}
+.tb .avatar img {
+ width: 100%;
+ border-radius: 50%;
+}
+.tb .avatar::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+ margin: -3px;
+ border-radius: 50%;
+ box-shadow: 1px 1px 3px 0 #000;
+ background: linear-gradient(135deg, #fff1eb, #ace0f9);
+}
+
+hr {
+ border: 0;
+ height: 2px;
+ background-image: linear-gradient(135deg, #bdc3c7 10%, #2c3e50);
+ border-radius: 10px;
+}
+
+.header {
+ max-width: 100%;
+ overflow: hidden;
+}
+.header hr {
+ margin: 5px 0px;
+}
+.header p {
+ font-size: 12px;
+ color: #2f4f4f;
+}
+.header h1 {
+ display: inline-block;
+ background-image: linear-gradient(271.14deg, #001bff 0.98%, #00f0ff 25.79%, #fce84a 47.33%, #f34628 65.77%, #b275ff 91.4%);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+}
+
+.info {
+ width: 100%;
+ display: flex;
+ justify-content: space-around;
+ font-weight: 700;
+}
+.info .li article {
+ width: 100px;
+ text-align: center;
+}
+.info .li article summary {
+ font-size: 20px;
+ margin-top: 5px;
+}
+.info .li article p {
+ font-size: 12px;
+ color: #2f4f4f;
+ white-space: nowrap;
+}
+
+.cpu {
+ width: 100px;
+ height: 100px;
+ background: #eee;
+ position: relative;
+ border-radius: 50%;
+}
+
+.left,
+.right {
+ width: 50px;
+ height: 100px;
+ position: absolute;
+ overflow: hidden;
+}
+
+.right {
+ right: 0;
+}
+.right .right-circle {
+ border-top-right-radius: 100px;
+ border-bottom-right-radius: 100px;
+ transform: rotate(180deg);
+ transform-origin: left center;
+}
+
+.left .left-circle,
+.right .right-circle {
+ width: 50px;
+ height: 100px;
+ background: #90ee90;
+}
+
+.left .left-circle {
+ border-top-left-radius: 100px;
+ border-bottom-left-radius: 100px;
+ transform: rotate(-180deg);
+ transform-origin: right center;
+}
+
+.inner {
+ width: 75px;
+ height: 75px;
+ border-radius: 50%;
+ text-align: center;
+ line-height: 75px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ color: #999;
+ font-size: 20px;
+ background: white;
+}
+
+.memory li {
+ margin: 10px;
+ display: flex;
+}
+.memory hr {
+ margin-bottom: 10px;
+}
+.memory .progress {
+ flex: 1;
+ height: 25px;
+ background: #c1c1c1;
+ margin: 0 5px;
+ position: relative;
+ border-radius: 5px;
+}
+.memory .progress .current {
+ background: #90ee90;
+ height: 25px;
+ border-radius: 5px;
+}
+.memory .progress .word {
+ position: absolute;
+ line-height: 25px;
+ left: 50%;
+ transform: translate(-50%, 0);
+ white-space: nowrap;
+}
+
+.HardDisk_li .mount {
+ min-width: 15px;
+ max-width: 3em;
+ line-height: 25px;
+ text-align: left;
+}
+.HardDisk_li .percentage {
+ min-width: 2em;
+ line-height: 25px;
+ text-align: center;
+}
+
+.speed {
+ width: 100%;
+ display: flex;
+ height: 25px;
+ line-height: 25px;
+}
+.speed p:first-child {
+ flex-grow: 1;
+ flex-shrink: 0;
+ max-width: 50%;
+ text-align: left;
+ margin-right: 20px;
+}
+.speed p:last-child {
+ flex-grow: 1;
+ flex-shrink: 1;
+ margin-left: 20px;
+ text-align: right;
+}/*# sourceMappingURL=state.css.map */
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/resources/state/state.html b/Yunzai/plugins/yenai-plugin/resources/state/state.html
new file mode 100644
index 0000000000000000000000000000000000000000..70ca221ed15adab05677bc9fd8b40ee4d1e704c8
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/resources/state/state.html
@@ -0,0 +1,196 @@
+{{extend defaultLayout}}
+
+{{block 'css'}}
+
+{{/block}}
+{{block 'main'}}
+{{@BotStatus}}
+
+
+ {{each visualData group}}
+ -
+
+
+
+
+ {{group.inner}}
+
+
+
+ {{group.title}}
+ {{each group.info info}}
+ {{info}}
+ {{/each}}
+
+
+ {{/each}}
+
+
+
+{{if HardDisk}}
+
+
+ {{each HardDisk}}
+ -
+
{{$value.mount}}
+
+
{{$value.used}} / {{$value.size}}
+
+
+ {{$value.use}}%
+
+ {{/each}}
+
+ {{if fsStats}}
+
+
fsStats
+
读 {{fsStats.rx_sec}}/s | 写 {{fsStats.wx_sec}}/s
+
+ {{/if}}
+
+{{/if}}
+
+{{if chartData}}
+
+
+{{/if}}
+{{if otherInfo}}
+
+ {{each otherInfo}}
+
+
{{$value.first}}
+
{{@$value.tail}}
+
+ {{/each}}
+
+{{/if}}
+
+{{if psTest}}
+
+ {{each psTest}}
+
+
{{$value.first}}
+
{{@$value.tail}}
+
+ {{/each}}
+
+{{/if}}
+
+{{@FastFetch}}
+
+{{/block}}
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/resources/state/state.scss b/Yunzai/plugins/yenai-plugin/resources/state/state.scss
new file mode 100644
index 0000000000000000000000000000000000000000..c293f91862b8481dd044a68eab965cdfcb266d93
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/resources/state/state.scss
@@ -0,0 +1,267 @@
+%text-overflow-mission {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+:root {
+ --high-color: #d73403;
+ --medium-color: #ffa500;
+ --low-color: #90ee90;
+}
+
+.container {
+ background: {
+ image: url('https://api.ghser.com/random/pe.php');
+ color: white;
+ position: center top;
+ repeat: no-repeat;
+ size: cover;
+ }
+}
+
+li {
+ list-style: none;
+}
+
+body {
+ display: flex;
+ height: 100%;
+ flex-direction: column;
+ justify-content: space-around;
+}
+
+.box {
+ margin: 20px;
+ padding: 10px;
+ background: rgba(255, 255, 255, 0.45);
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
+ backdrop-filter: blur(10px);
+ border-radius: 10px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ font-weight: 700;
+}
+
+.tb {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .avatar {
+ position: relative;
+ height: 100px;
+ width: 100px;
+ border-radius: 50%;
+ margin: 0 20px;
+ flex-shrink: 0;
+
+ img {
+ width: 100%;
+ border-radius: 50%;
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+ margin: -3px;
+ border-radius: 50%;
+ box-shadow: 1px 1px 3px 0 #000;
+ background: linear-gradient(135deg, #fff1eb, #ace0f9);
+ }
+ }
+}
+
+hr {
+ border: 0;
+ height: 2px;
+ background-image: linear-gradient(135deg, #bdc3c7 10%, #2c3e50);
+ border-radius: 10px;
+}
+
+.header {
+ max-width: 100%;
+ overflow: hidden;
+
+ hr {
+ margin: 5px 0px;
+ }
+
+ p {
+ font-size: 12px;
+ color: #2f4f4f;
+ }
+
+ h1 {
+ @extend %text-overflow-mission;
+ display: inline-block;
+ background-image: linear-gradient(271.14deg,
+ #001bff 0.98%,
+ #00f0ff 25.79%,
+ #fce84a 47.33%,
+ #f34628 65.77%,
+ #b275ff 91.4%);
+ background-clip: text;
+ color: transparent;
+ }
+}
+
+.info {
+ width: 100%;
+ display: flex;
+ justify-content: space-around;
+ font-weight: 700;
+
+ .li {
+ article {
+ width: 100px;
+ text-align: center;
+
+ summary {
+ font-size: 20px;
+ margin-top: 5px;
+ }
+
+ p {
+ font-size: 12px;
+ color: #2f4f4f;
+ white-space: nowrap;
+ }
+ }
+ }
+}
+
+.cpu {
+ width: 100px;
+ height: 100px;
+ background: #eee;
+ position: relative;
+ border-radius: 50%;
+}
+
+.left,
+.right {
+ width: 50px;
+ height: 100px;
+ position: absolute;
+ overflow: hidden;
+}
+
+.right {
+ right: 0;
+
+ .right-circle {
+ border-top-right-radius: 100px;
+ border-bottom-right-radius: 100px;
+ transform: rotate(180deg);
+ transform-origin: left center;
+ }
+}
+
+.left .left-circle,
+.right .right-circle {
+ width: 50px;
+ height: 100px;
+ background: #90ee90;
+}
+
+.left {
+ .left-circle {
+ border-top-left-radius: 100px;
+ border-bottom-left-radius: 100px;
+ transform: rotate(-180deg);
+ transform-origin: right center;
+ }
+}
+
+.inner {
+ width: 75px;
+ height: 75px;
+ border-radius: 50%;
+ text-align: center;
+ line-height: 75px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ color: #999;
+ font-size: 20px;
+ background: white;
+}
+
+.memory {
+ li {
+ margin: 10px;
+ display: flex;
+ }
+
+ hr {
+ margin-bottom: 10px;
+ }
+
+ .progress {
+ flex: 1;
+ height: 25px;
+ background: #c1c1c1;
+ margin: 0 5px;
+ position: relative;
+ border-radius: 5px;
+
+ .current {
+ background: #90ee90;
+ height: 25px;
+ border-radius: 5px;
+ }
+
+ .word {
+ position: absolute;
+ line-height: 25px;
+ left: 50%;
+ transform: translate(-50%, 0);
+ white-space: nowrap;
+ }
+ }
+}
+
+.HardDisk_li {
+ .mount {
+ @extend %text-overflow-mission;
+ min-width: 15px;
+ max-width: 3em;
+ line-height: 25px;
+ text-align: left;
+ }
+
+ .percentage {
+ min-width: 2em;
+ line-height: 25px;
+ text-align: center;
+ }
+}
+
+.speed {
+ width: 100%;
+ display: flex;
+ height: 25px;
+ line-height: 25px;
+
+ p {
+ @extend %text-overflow-mission;
+
+ &:first-child {
+ flex-grow: 1;
+ flex-shrink: 0;
+ max-width: 50%;
+ text-align: left;
+ margin-right: 20px;
+ }
+
+ &:last-child {
+ flex-grow: 1;
+ flex-shrink: 1;
+ margin-left: 20px;
+ text-align: right;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/resources/state/state.sh b/Yunzai/plugins/yenai-plugin/resources/state/state.sh
new file mode 100644
index 0000000000000000000000000000000000000000..5c332d98e3fb815e71609da00e4a822c74524e08
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/resources/state/state.sh
@@ -0,0 +1,30 @@
+echo -n ""
+if type fastfetch &>/dev/null;then
+ if [ "$(uname)" = Linux ];then
+ fastfetch --pipe
+ else
+ fastfetch --stdout
+ fi
+else
+ bash <(curl -L https://gitee.com/TimeRainStarSky/neofetch/raw/master/neofetch) --stdout
+fi|\
+sed -n 's|: |
|p'|\
+while read i;do
+ echo -n "
"
+done
+echo "
"
+if type getprop &>/dev/null;then
+ echo -n ""
+ echo "设备代号:$(getprop ro.product.device)
+ 设备型号:$(getprop ro.product.marketname) ($(getprop ro.product.name))
+ 认证型号:$(getprop ro.product.model)
+ 安卓版本:$(getprop ro.build.version.release) (SDK $(getprop ro.build.version.sdk))
+ 系统版本:$(getprop ro.build.version.incremental) ($(getprop ro.build.display.id))
+ 编译时间:$(date -d "@$(getprop ro.build.date.utc)" "+%F %T")
+ 基带版本:$(getprop gsm.version.baseband|cut -d "," -f1)"|\
+ sed -n 's|:|
|p'|\
+ while read i;do
+ echo -n "
"
+ done
+ echo "
"
+fi
\ No newline at end of file
diff --git a/Yunzai/plugins/yenai-plugin/resources/state/theme_westeros.json b/Yunzai/plugins/yenai-plugin/resources/state/theme_westeros.json
new file mode 100644
index 0000000000000000000000000000000000000000..c8329b0a423515658d7ed1b020e339654966832f
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/resources/state/theme_westeros.json
@@ -0,0 +1,415 @@
+{
+ "color": [
+ "#2ec7c9",
+ "#b6a2de",
+ "#5ab1ef",
+ "#ffb980",
+ "#d87a80",
+ "#8d98b3",
+ "#e5cf0d",
+ "#97b552",
+ "#95706d",
+ "#dc69aa",
+ "#07a2a4",
+ "#9a7fd1",
+ "#588dd5",
+ "#f5994e",
+ "#c05050",
+ "#59678c",
+ "#c9ab00",
+ "#7eb00a",
+ "#6f5553",
+ "#c14089"
+ ],
+ "backgroundColor": "rgba(0,0,0,0)",
+ "textStyle": {},
+ "title": {
+ "textStyle": {
+ "color": "#008acd"
+ },
+ "subtextStyle": {
+ "color": "#aaaaaa"
+ }
+ },
+ "line": {
+ "itemStyle": {
+ "borderWidth": 1
+ },
+ "lineStyle": {
+ "width": 2
+ },
+ "symbolSize": "3",
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "radar": {
+ "itemStyle": {
+ "borderWidth": 1
+ },
+ "lineStyle": {
+ "width": 2
+ },
+ "symbolSize": "3",
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "bar": {
+ "itemStyle": {
+ "barBorderWidth": 0,
+ "barBorderColor": "#ccc"
+ }
+ },
+ "pie": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "scatter": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "boxplot": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "parallel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "sankey": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "funnel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "gauge": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "candlestick": {
+ "itemStyle": {
+ "color": "#d87a80",
+ "color0": "#2ec7c9",
+ "borderColor": "#d87a80",
+ "borderColor0": "#2ec7c9",
+ "borderWidth": 1
+ }
+ },
+ "graph": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ },
+ "lineStyle": {
+ "width": 1,
+ "color": "#aaa"
+ },
+ "symbolSize": "3",
+ "symbol": "emptyCircle",
+ "smooth": true,
+ "color": [
+ "#2ec7c9",
+ "#b6a2de",
+ "#5ab1ef",
+ "#ffb980",
+ "#d87a80",
+ "#8d98b3",
+ "#e5cf0d",
+ "#97b552",
+ "#95706d",
+ "#dc69aa",
+ "#07a2a4",
+ "#9a7fd1",
+ "#588dd5",
+ "#f5994e",
+ "#c05050",
+ "#59678c",
+ "#c9ab00",
+ "#7eb00a",
+ "#6f5553",
+ "#c14089"
+ ],
+ "label": {
+ "color": "#000000"
+ }
+ },
+ "map": {
+ "itemStyle": {
+ "areaColor": "#dddddd",
+ "borderColor": "#eeeeee",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#d87a80"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(254,153,78,1)",
+ "borderColor": "#444",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(100,0,0)"
+ }
+ }
+ },
+ "geo": {
+ "itemStyle": {
+ "areaColor": "#dddddd",
+ "borderColor": "#eeeeee",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#d87a80"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(254,153,78,1)",
+ "borderColor": "#444",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(100,0,0)"
+ }
+ }
+ },
+ "categoryAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333333"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#aaaaaa"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ }
+ },
+ "valueAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333333"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#aaaaaa"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ }
+ },
+ "logAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333333"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#aaaaaa"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ }
+ },
+ "timeAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333333"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#aaaaaa"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ }
+ },
+ "toolbox": {
+ "iconStyle": {
+ "borderColor": "#2ec7c9"
+ },
+ "emphasis": {
+ "iconStyle": {
+ "borderColor": "#18a4a6"
+ }
+ }
+ },
+ "legend": {
+ "textStyle": {
+ "color": "#333333"
+ }
+ },
+ "tooltip": {
+ "axisPointer": {
+ "lineStyle": {
+ "color": "#008acd",
+ "width": "1"
+ },
+ "crossStyle": {
+ "color": "#008acd",
+ "width": "1"
+ }
+ }
+ },
+ "timeline": {
+ "lineStyle": {
+ "color": "#008acd",
+ "width": 1
+ },
+ "itemStyle": {
+ "color": "#008acd",
+ "borderWidth": 1
+ },
+ "controlStyle": {
+ "color": "#008acd",
+ "borderColor": "#008acd",
+ "borderWidth": 0.5
+ },
+ "checkpointStyle": {
+ "color": "#2ec7c9",
+ "borderColor": "#2ec7c9"
+ },
+ "label": {
+ "color": "#008acd"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "color": "#a9334c"
+ },
+ "controlStyle": {
+ "color": "#008acd",
+ "borderColor": "#008acd",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#008acd"
+ }
+ }
+ },
+ "visualMap": {
+ "color": [
+ "#5ab1ef",
+ "#e0ffff"
+ ]
+ },
+ "dataZoom": {
+ "backgroundColor": "rgba(47,69,84,0)",
+ "dataBackgroundColor": "#efefff",
+ "fillerColor": "rgba(182,162,222,0.2)",
+ "handleColor": "#008acd",
+ "handleSize": "100%",
+ "textStyle": {
+ "color": "#333333"
+ }
+ },
+ "markPoint": {
+ "label": {
+ "color": "#000000"
+ },
+ "emphasis": {
+ "label": {
+ "color": "#000000"
+ }
+ }
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/tools/cronValidate.js b/Yunzai/plugins/yenai-plugin/tools/cronValidate.js
new file mode 100644
index 0000000000000000000000000000000000000000..544723e8515a6c360dace892f11beef352e1a631
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/tools/cronValidate.js
@@ -0,0 +1,428 @@
+/*! !!!!!!
+以下为凶残的cron表达式验证,胆小肾虚及心脏病者慎入!!!
+不听劝告者后果自负T T
+!!!!!!!
+cron表达式为秒,分,时,日,月,周,年
+判断正误方法:错误的话返回错误信息,正确的话返回true
+*/
+// 返回错误信息用
+let message = ''
+export default function cronValidate (cronExpression) {
+ // 先将cron表达式进行分割
+ let cronParams = cronExpression.split(' ')
+ // 判断cron表达式是否具有该具有的属性长度,没有年份的长度为6,带年份的长度为7,其他情况都是错误的
+ if (cronParams.length < 6 || cronParams.length > 7) {
+ return 'cron表达式需要输入6-7位参数,请重新输入'
+ } else {
+ // 日和周必须有一个为?,或者全为*
+ if ((cronParams[3] == '?' && cronParams[5] != '?') || (cronParams[5] == '?' && cronParams[3] != '?') || (cronParams[3] == '*' && cronParams[5] == '*')) {
+ // 检查第一位的秒是否正确
+ message = checkSecondsField(cronParams[0])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第二位的分是否正确
+ message = checkMinutesField(cronParams[1])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第三位的时是否正确
+ message = checkHoursField(cronParams[2])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第四位的日是否正确
+ message = checkDayOfMonthField(cronParams[3])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第五位的月是否正确
+ message = checkMonthsField(cronParams[4])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第6位的周是否正确
+ message = checkDayOfWeekField(cronParams[5])
+ if (message != true) {
+ return message
+ }
+
+ // 检查第七位的年是否正确
+ if (cronParams.length > 6) {
+ message = checkYearField(cronParams[6])
+ if (message != true) {
+ return message
+ }
+ }
+
+ return true
+ } else {
+ return '指定日时周必须设为不指定(?),指定周时日必须设为不指定(?)'
+ }
+ }
+}
+
+// 检查秒的函数方法
+function checkSecondsField (secondsField) {
+ return checkField(secondsField, 0, 59, '秒')
+}
+
+// 检查分的函数方法
+function checkMinutesField (minutesField) {
+ return checkField(minutesField, 0, 59, '分')
+}
+
+// 检查小时的函数方法
+function checkHoursField (hoursField) {
+ return checkField(hoursField, 0, 23, '时')
+}
+
+// 检查日期的函数方法
+function checkDayOfMonthField (dayOfMonthField) {
+ if (dayOfMonthField == '?') {
+ return true
+ }
+ if (dayOfMonthField.indexOf('L') >= 0) {
+ return checkFieldWithLetter(dayOfMonthField, 'L', 1, 7, '日')
+ } else if (dayOfMonthField.indexOf('W') >= 0) {
+ return checkFieldWithLetter(dayOfMonthField, 'W', 1, 31, '日')
+ } else if (dayOfMonthField.indexOf('C') >= 0) {
+ return checkFieldWithLetter(dayOfMonthField, 'C', 1, 31, '日')
+ }
+ return checkField(dayOfMonthField, 1, 31, '日')
+}
+
+// 检查月份的函数方法
+function checkMonthsField (monthsField) {
+ // 月份简写处理
+ if (monthsField != '*') {
+ monthsField = monthsField.replace('JAN', '1')
+ monthsField = monthsField.replace('FEB', '2')
+ monthsField = monthsField.replace('MAR', '3')
+ monthsField = monthsField.replace('APR', '4')
+ monthsField = monthsField.replace('MAY', '5')
+ monthsField = monthsField.replace('JUN', '6')
+ monthsField = monthsField.replace('JUL', '7')
+ monthsField = monthsField.replace('AUG', '8')
+ monthsField = monthsField.replace('SEP', '9')
+ monthsField = monthsField.replace('OCT', '10')
+ monthsField = monthsField.replace('NOV', '11')
+ monthsField = monthsField.replace('DEC', '12')
+ return checkField(monthsField, 1, 12, '月份')
+ } else {
+ return true
+ }
+}
+
+// 星期验证
+function checkDayOfWeekField (dayOfWeekField) {
+ dayOfWeekField = dayOfWeekField.replace('SUN', '1')
+ dayOfWeekField = dayOfWeekField.replace('MON', '2')
+ dayOfWeekField = dayOfWeekField.replace('TUE', '3')
+ dayOfWeekField = dayOfWeekField.replace('WED', '4')
+ dayOfWeekField = dayOfWeekField.replace('THU', '5')
+ dayOfWeekField = dayOfWeekField.replace('FRI', '6')
+ dayOfWeekField = dayOfWeekField.replace('SAT', '7')
+ if (dayOfWeekField == '?') {
+ return true
+ }
+ if (dayOfWeekField.indexOf('L') >= 0) {
+ return checkFieldWithLetterWeek(dayOfWeekField, 'L', 1, 7, '星期')
+ } else if (dayOfWeekField.indexOf('C') >= 0) {
+ return checkFieldWithLetterWeek(dayOfWeekField, 'C', 1, 7, '星期')
+ } else if (dayOfWeekField.indexOf('#') >= 0) {
+ return checkFieldWithLetterWeek(dayOfWeekField, '#', 1, 7, '星期')
+ } else {
+ return checkField(dayOfWeekField, 1, 7, '星期')
+ }
+}
+
+// 检查年份的函数方法
+function checkYearField (yearField) {
+ return checkField(yearField, 1970, 2099, '年的')
+}
+
+// 通用的检查值的大小范围的方法( - , / *)
+function checkField (value, minimal, maximal, attribute) {
+ // 校验值中是否有“-”,如果有“-”的话,下标会>0
+ if (value.indexOf('-') > -1) {
+ return checkRangeAndCycle(value, minimal, maximal, attribute)
+ } else if (value.indexOf(',') > -1) {
+ // 校验值中是否有“,”,如果有“,”的话,下标会>0
+ return checkListField(value, minimal, maximal, attribute)
+ } else if (value.indexOf('/') > -1) {
+ // 校验值中是否有“/”,如果有“/”的话,下标会>0
+ return checkIncrementField(value, minimal, maximal, attribute)
+ } else if (value == '*') {
+ // 校验值是否为“*”
+ return true
+ } else {
+ // 校验单独的数字,英文字母,以及各种神奇的符号等...
+ return checkIntValue(value, minimal, maximal, true, attribute)
+ }
+}
+
+// 检测是否是整数以及是否在范围内,参数:检测的值,下限,上限,是否检查端点,检查的属性
+function checkIntValue (value, minimal, maximal, checkExtremity, attribute) {
+ try {
+ // 用10进制犯法来进行整数转换
+ let val = parseInt(value, 10)
+ if (value == val) {
+ if (checkExtremity) {
+ if (val < minimal || val > maximal) {
+ return (attribute + '的参数取值范围必须在' + minimal + '-' + maximal + '之间')
+ }
+ return true
+ }
+ return true
+ }
+ return (attribute + '的参数存在非法字符,必须为整数或允许的大写英文')
+ } catch (e) {
+ return (attribute + '的参数有非法字符,必须是整数~')
+ }
+}
+// 检验枚举类型的参数是否正确
+function checkListField (value, minimal, maximal, attribute) {
+ let st = value.split(',')
+ let values = new Array(st.length)
+ // 计算枚举的数字在数组中中出现的次数,出现一次为没有重复的。
+ let count = 0
+ for (let j = 0; j < st.length; j++) {
+ values[j] = st[j]
+ }
+ // 判断枚举类型的值是否重复
+ for (let i = 0; i < values.length; i++) {
+ // 判断枚举的值是否在范围内
+ message = checkIntValue(values[i], minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ count = 0
+ for (let j = 0; j < values.length; j++) {
+ if (values[i] == values[j]) {
+ count++
+ }
+ if (count > 1) {
+ return (attribute + '中的参数重复')
+ }
+ }
+ }
+ let previousValue = -1
+ // 判断枚举的值是否排序正确
+ for (let i = 0; i < values.length; i++) {
+ let currentValue = values[i]
+ try {
+ let val = parseInt(currentValue, 10)
+ if (val < previousValue) {
+ return (attribute + '的参数应该从小到大')
+ } else {
+ previousValue = val
+ }
+ } catch (e) {
+ // 前面验证过了,这边的代码不可能跑到
+ return ('这段提示用不到')
+ }
+ }
+ return true
+}
+
+// 检验循环
+function checkIncrementField (value, minimal, maximal, attribute) {
+ if (value.split('/').length > 2) {
+ return (attribute + "中的参数只能有一个'/'")
+ }
+ let start = value.substring(0, value.indexOf('/'))
+ let increment = value.substring(value.indexOf('/') + 1)
+ if (start != '*') {
+ // 检验前值是否正确
+ message = checkIntValue(start, minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ // 检验后值是否正确
+ message = checkIntValue(increment, minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ return true
+ } else {
+ // 检验后值是否正确
+ return checkIntValue(increment, minimal, maximal, false, attribute)
+ }
+}
+
+// 检验范围
+function checkRangeAndCycle (params, minimal, maximal, attribute) {
+ // 校验“-”符号是否只有一个
+ if (params.split('-').length > 2) {
+ return (attribute + "中的参数只能有一个'-'")
+ }
+ let value = null
+ let cycle = null
+ // 检验范围内是否有嵌套周期
+ if (params.indexOf('/') > -1) {
+ // 校验“/”符号是否只有一个
+ if (params.split('/').length > 2) {
+ return (attribute + "中的参数只能有一个'/'")
+ }
+ value = params.split('/')[0]
+ cycle = params.split('/')[1]
+ // 判断循环的参数是否正确
+ message = checkIntValue(cycle, minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ } else {
+ value = params
+ }
+ let startValue = value.substring(0, value.indexOf('-'))
+ let endValue = value.substring(value.indexOf('-') + 1)
+ // 判断参数范围的第一个值是否正确
+ message = checkIntValue(startValue, minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ // 判断参数范围的第二个值是否正确
+ message = checkIntValue(endValue, minimal, maximal, true, attribute)
+ if (message != true) {
+ return message
+ }
+ // 判断参数的范围前值是否小于后值
+ try {
+ let startVal = parseInt(startValue, 10)
+ let endVal = parseInt(endValue, 10)
+ if (endVal < startVal) {
+ return (attribute + '的取值范围错误,前值必须小于后值')
+ }
+ if ((endVal - startVal) < parseInt(cycle, 10)) {
+ return (attribute + '的取值范围内的循环无意义')
+ }
+ return true
+ } catch (e) {
+ // 用不到这行代码的
+ return (attribute + '的参数有非法字符,必须是整数')
+ }
+}
+
+// 检查日中的特殊字符
+function checkFieldWithLetter (value, letter, minimalBefore, maximalBefore, attribute) {
+ // 判断是否只有一个字母
+ for (let i = 0; i < value.length; i++) {
+ let count = 0
+ if (value.charAt(i) == letter) {
+ count++
+ }
+ if (count > 1) {
+ return (attribute + '的值的' + letter + '字母只能有一个')
+ }
+ }
+ // 校验L
+ if (letter == 'L') {
+ if (value == 'LW') {
+ return true
+ }
+ if (value == 'L') {
+ return true
+ }
+ if (value.endsWith('LW') && value.length > 2) {
+ return (attribute + '中的参数,最后的LW前面不能有任何字母参数')
+ }
+ if (!value.endsWith('L')) {
+ return (attribute + '中的参数,L字母后面不能有W以外的字符、数字等')
+ } else {
+ let num = value.substring(0, value.indexOf(letter))
+ return checkIntValue(num, minimalBefore, maximalBefore, true, attribute)
+ }
+ }
+
+ // 校验W
+ if (letter == 'W') {
+ if (!value.endsWith('W')) {
+ return (attribute + '中的参数的W必须作为结尾')
+ } else {
+ if (value == 'W') {
+ return (attribute + '中的参数的W前面必须有数字')
+ }
+ let num = value.substring(0, value.indexOf(letter))
+ return checkIntValue(num, minimalBefore, maximalBefore, true, attribute)
+ }
+ }
+
+ if (letter == 'C') {
+ if (!value.endsWith('C')) {
+ return (attribute + '中的参数的C必须作为结尾')
+ } else {
+ if (value == 'C') {
+ return (attribute + '中的参数的C前面必须有数字')
+ }
+ let num = value.substring(0, value.indexOf(letter))
+ return checkIntValue(num, minimalBefore, maximalBefore, true, attribute)
+ }
+ }
+}
+
+// 检查星期中的特殊字符
+function checkFieldWithLetterWeek (value, letter, minimalBefore, maximalBefore, attribute) {
+ // 判断是否只有一个字母
+ for (let i = 0; i < value.length; i++) {
+ let count = 0
+ if (value.charAt(i) == letter) {
+ count++
+ }
+ if (count > 1) {
+ return (attribute + '的值的' + letter + '字母只能有一个')
+ }
+ }
+ // 校验L
+ if (letter == 'L') {
+ if (value == 'L') {
+ return true
+ }
+ if (!value.endsWith('L')) {
+ return (attribute + '中的参数,L字母必须是最后一位')
+ } else {
+ let num = value.substring(0, value.indexOf(letter))
+ return checkIntValue(num, minimalBefore, maximalBefore, true, attribute)
+ }
+ }
+
+ if (letter == 'C') {
+ if (!value.endsWith('C')) {
+ return (attribute + '中的参数的C必须作为结尾')
+ } else {
+ if (value == 'C') {
+ return (attribute + '中的参数的C前面必须有数字')
+ }
+ let num = value.substring(0, value.indexOf(letter))
+ return checkIntValue(num, minimalBefore, maximalBefore, true, attribute)
+ }
+ }
+
+ if (letter == '#') {
+ if (value == '#') {
+ return (attribute + '中的#前后必须有整数')
+ }
+ if (value.charAt(0) == letter) {
+ return (attribute + '中的#前面必须有整数')
+ }
+ if (value.endsWith('#')) {
+ return (attribute + '中的#后面必须有整数')
+ }
+ let num1 = value.substring(0, value.indexOf(letter))
+ let num2 = value.substring(value.indexOf(letter) + 1, value.length)
+ message = checkIntValue(num1, 1, 4, true, (attribute + '的#前面'))
+ if (message != true) {
+ return message
+ }
+ message = checkIntValue(num2, minimalBefore, maximalBefore, true, (attribute + '的#后面'))
+ if (message != true) {
+ return message
+ }
+ return true
+ }
+}
diff --git a/Yunzai/plugins/yenai-plugin/tools/sagiri.js b/Yunzai/plugins/yenai-plugin/tools/sagiri.js
new file mode 100644
index 0000000000000000000000000000000000000000..22607cb12edd17a00c51fe59987c59f775af1475
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/tools/sagiri.js
@@ -0,0 +1,381 @@
+/* eslint-disable no-void */
+const DoujinMangaLexicon = {
+ name: 'The Doujinshi & Manga Lexicon',
+ index: 3,
+ urlMatcher: /(?:http:\/\/)?doujinshi\.mugimugi\.org\/index\.php?p=book&id=\d+/i,
+ backupUrl: ({ data: { ddb_id } }) => `http://doujinshi.mugimugi.org/index.php?P=BOOK&ID=${ddb_id}`
+}
+const Pixiv = {
+ name: 'Pixiv',
+ index: 5,
+ urlMatcher: /(?:https?:\/\/)?(?:www\.)?pixiv\.net\/member_illust\.php\?mode=.+&illust_id=\d+/i,
+ backupUrl: ({ data: { pixiv_id } }) => `https://www.pixiv.net/artworks/${pixiv_id}`,
+ authorData: ({ member_id, member_name }) => ({
+ authorName: member_name,
+ authorUrl: `https://www.pixiv.net/users/${member_id}`
+ })
+}
+const NicoNicoSeiga = {
+ name: 'Nico Nico Seiga',
+ index: 8,
+ urlMatcher: /(?:http:\/\/)?seiga\.nicovideo\.jp\/seiga\/im\d+/i,
+ backupUrl: ({ data: { seiga_id } }) => `http://seiga.nicovideo.jp/seiga/im${seiga_id}`
+}
+const Danbooru = {
+ name: 'Danbooru',
+ index: 9,
+ urlMatcher: /(?:https?:\/\/)?danbooru\.donmai\.us\/(?:posts|post\/show)\/\d+/i,
+ backupUrl: ({ data: { danbooru_id } }) => `https://danbooru.donmai.us/posts/${danbooru_id}`
+}
+const Drawr = {
+ name: 'drawr',
+ index: 10,
+ urlMatcher: /(?:http:\/\/)?(?:www\.)?drawr\.net\/show\.php\?id=\d+/i,
+ backupUrl: ({ data: { drawr_id } }) => `http://drawr.net/show.php?id=${drawr_id}`
+}
+const Nijie = {
+ name: 'Nijie',
+ index: 11,
+ urlMatcher: /(?:http:\/\/)?nijie\.info\/view\.php\?id=\d+/i,
+ backupUrl: (data) => `http://nijie.info/view.php?id=${data.data.nijie_id}`
+}
+const Yandere = {
+ name: 'Yande.re',
+ index: 12,
+ urlMatcher: /(?:https?:\/\/)?yande\.re\/post\/show\/\d+/i,
+ backupUrl: (data) => `https://yande.re/post/show/${data.data.yandere_id}`
+}
+const OpeningsMoe = {
+ name: 'Openings.moe',
+ index: 13,
+ urlMatcher: /(?:https?:\/\/)?openings\.moe\/\?video=.*/,
+ backupUrl: (data) => `https://openings.moe/?video=${data.data.file}`
+}
+const Fakku = {
+ name: 'FAKKU',
+ index: 16,
+ urlMatcher: /(?:https?:\/\/)?(www\.)?fakku\.net\/hentai\/[a-z-]+\d+}/i,
+ backupUrl: (data) => { let _a; return `https://www.fakku.net/hentai/${(_a = data.data.source) === null || _a === void 0 ? void 0 : _a.toLowerCase().replace(' ', '-')}` }
+}
+const NHentai = {
+ name: 'nHentai',
+ index: 18,
+ urlMatcher: /https?:\/\/nhentai.net\/g\/\d+/i,
+ backupUrl: (data) => { let _a; return `https://nhentai.net/g/${(_a = data.header.thumbnail.match(/nhentai\/(\d+)/)) === null || _a === void 0 ? void 0 : _a[1]}` }
+}
+const TwoDMarket = {
+ name: '2D-Market',
+ index: 19,
+ urlMatcher: /https?:\/\/2d-market\.com\/comic\/\d+/i,
+ backupUrl: (data) => {
+ let _a, _b
+ return `http://2d-market.com/Comic/${(_a = data.header.thumbnail.match(/2d_market\/(\d+)/i)) === null || _a === void 0 ? void 0 : _a[1]}-${(_b = data.data.source) === null || _b === void 0 ? void 0 : _b.replace(' ', '-')}`
+ }
+}
+const MediBang = {
+ name: 'MediBang',
+ index: 20,
+ urlMatcher: /(?:https?:\/\/)?medibang\.com\/picture\/[\da-z]+/i,
+ backupUrl: (data) => data.data.url
+}
+const AniDB = {
+ name: 'AniDB',
+ index: 21,
+ urlMatcher: /(?:https?:\/\/)?anidb\.net\/perl-bin\/animedb\.pl\?show=.+&aid=\d+/i,
+ backupUrl: (data) => `https://anidb.net/perl-bin/animedb.pl?show=anime&aid=${data.data.anidb_aid}`
+}
+const IMDb = {
+ name: 'IMDb',
+ index: 23,
+ urlMatcher: /(?:https?:\/\/)?(?:www\.)?imdb\.com\/title\/.+/i,
+ backupUrl: (data) => `https://www.imdb.com/title/${data.data.imdb_id}`
+}
+const Gelbooru = {
+ name: 'Gelbooru',
+ index: 25,
+ urlMatcher: /(?:https?:\/\/)gelbooru\.com\/index\.php\?page=post&s=view&id=\d+/i,
+ backupUrl: (data) => `https://gelbooru.com/index.php?page=post&s=view&id=${data.data.gelbooru_id}`
+}
+const Konachan = {
+ name: 'Konachan',
+ index: 26,
+ urlMatcher: /(?:http:\/\/)?konachan\.com\/post\/show\/\d+/i,
+ backupUrl: (data) => `https://konachan.com/post/show/${data.data.konachan_id}`
+}
+const SankakuChannel = {
+ name: 'Sankaku Channel',
+ index: 27,
+ urlMatcher: /(?:https?:\/\/)?chan\.sankakucomplex\.com\/post\/show\/\d+/i,
+ backupUrl: (data) => `https://chan.sankakucomplex.com/post/show/${data.data.sankaku_id}`
+}
+const AnimePictures = {
+ name: 'Anime-Pictures',
+ index: 28,
+ urlMatcher: /(?:https?:\/\/)?anime-pictures\.net\/pictures\/view_post\/\d+/i,
+ backupUrl: (data) => `https://anime-pictures.net/pictures/view_post/${data.data['anime-pictures_id']}`
+}
+const E621 = {
+ name: 'e621',
+ index: 29,
+ urlMatcher: /(?:https?:\/\/)?e621\.net\/post\/show\/\d+/i,
+ backupUrl: (data) => `https://e621.net/post/show/${data.data.e621_id}`
+}
+const IdolComplex = {
+ name: 'Idol Complex',
+ index: 30,
+ urlMatcher: /(?:https?:\/\/)?idol\.sankakucomplex\.com\/post\/show\/\d+/i,
+ backupUrl: (data) => `https://idol.sankakucomplex.com/post/show/${data.data.idol_id}`
+}
+const bcyIllust = {
+ name: 'bcy.net Illust',
+ index: 31,
+ urlMatcher: /(?:http:\/\/)?bcy.net\/illust\/detail\/\d+/i,
+ backupUrl: (data) => `https://bcy.net/${data.data.bcy_type}/detail/${data.data.member_link_id}/${data.data.bcy_id}`,
+ authorData: ({ member_id, member_name }) => ({
+ authorName: member_name,
+ authorUrl: `https://bcy.net/u/${member_id}`
+ })
+}
+const bcyCosplay = {
+ name: 'bcy.net Cosplay',
+ index: 32,
+ urlMatcher: /(?:http:\/\/)?bcy.net\/coser\/detail\/\d{5}/i,
+ backupUrl: (data) => `https://bcy.net/${data.data.bcy_type}/detail/${data.data.member_link_id}/${data.data.bcy_id}`
+}
+const PortalGraphics = {
+ name: 'PortalGraphics',
+ index: 33,
+ urlMatcher: /(?:http:\/\/)?web\.archive\.org\/web\/http:\/\/www\.portalgraphics\.net\/pg\/illust\/\?image_id=\d+/i,
+ backupUrl: (data) => `http://web.archive.org/web/http://www.portalgraphics.net/pg/illust/?image_id=${data.data.pg_id}`
+}
+const DeviantArt = {
+ name: 'deviantArt',
+ index: 34,
+ urlMatcher: /(?:https:\/\/)?deviantart\.com\/view\/\d+/i,
+ backupUrl: (data) => `https://deviantart.com/view/${data.data.da_id}`,
+ authorData: ({ author_name: authorName, author_url: authorUrl }) => ({
+ authorName,
+ authorUrl
+ })
+}
+const Pawoo = {
+ name: 'Pawoo',
+ index: 35,
+ urlMatcher: /(?:https?:\/\/)?pawoo\.net\/@.+/i,
+ backupUrl: (data) => `https://pawoo.net/@${data.data.user_acct}/${data.data.pawoo_id}`
+}
+const MangaUpdates = {
+ name: 'Manga Updates',
+ index: 36,
+ urlMatcher: /(?:https:\/\/)?www\.mangaupdates\.com\/series\.html\?id=\d+/gi,
+ backupUrl: (data) => `https://www.mangaupdates.com/series.html?id=${data.data.mu_id}`
+}
+const MangaDex = {
+ name: 'MangaDex',
+ index: 37,
+ urlMatcher: /(?:https?:\/\/)?mangadex\.org\/chapter\/(\w|-)+\/(?:\d+)?/gi,
+ backupUrl: (data) => `https://mangadex.org/chapter/${data.data.md_id}`,
+ authorData: (data) => ({
+ authorName: data.author,
+ authorUrl: null
+ })
+}
+const ArtStation = {
+ name: 'FurAffinity',
+ index: 39,
+ urlMatcher: /(?:https?:\/\/)?www\.artstation\.com\/artwork\/\w+/i,
+ backupUrl: (data) => `https://www.artstation.com/artwork/${data.data.as_project}`,
+ authorData: (data) => ({
+ authorName: data.author_name,
+ authorUrl: data.author_url
+ })
+}
+const FurAffinity = {
+ name: 'FurAffinity',
+ index: 40,
+ urlMatcher: /(?:https?:\/\/)?furaffinity\.net\/view\/\d+/i,
+ backupUrl: (data) => `https://furaffinity.net/view/${data.data.fa_id}`,
+ authorData: (data) => ({
+ authorName: data.author_name,
+ authorUrl: data.author_url
+ })
+}
+const Twitter = {
+ name: 'Twitter',
+ index: 41,
+ urlMatcher: /(?:https?:\/\/)?twitter\.com\/.+/i,
+ backupUrl: (data) => `https://twitter.com/i/web/status/${data.data.tweet_id}`,
+ authorData: (data) => ({
+ authorName: data.twitter_user_handle,
+ authorUrl: `https://twitter.com/i/user/${data.twitter_user_id}`
+ })
+}
+const FurryNetwork = {
+ name: 'Furry Network',
+ index: 42,
+ urlMatcher: /(?:https?:\/\/)?furrynetwork\.com\/artwork\/\d+/i,
+ backupUrl: (data) => `https://furrynetwork.com/artwork/${data.data.fn_id}`,
+ authorData: (data) => ({
+ authorName: data.author_name,
+ authorUrl: data.author_url
+ })
+}
+const Kemono = {
+ name: 'Kemono',
+ index: 43,
+ urlMatcher: /|(?:(?:https?:\/\/)?fantia\.jp\/posts\/\d+)|(?:(?:https?:\/\/)?subscribestar\.adult\/posts\/\d+)|(?:(?:https?:\/\/)?gumroad\.com\/l\/\w+)|(?:(?:https?:\/\/)?patreon\.com\/posts\/\d+)|(?:(?:https?:\/\/)?pixiv\.net\/fanbox\/creator\/\d+\/post\/\d+)|(?:(?:https?:\/\/)?dlsite\.com\/home\/work\/=\/product_id\/\w+\.\w+)/i,
+ backupUrl: (data) => {
+ switch (data.data.service) {
+ case 'fantia':
+ return `https://fantia.jp/posts/${data.data.id}`
+ case 'subscribestar':
+ return `https://subscribestar.adult/posts/${data.data.id}`
+ case 'gumroad':
+ return `https://gumroad.com/l/${data.data.id}`
+ case 'patreon':
+ return `https://patreon.com/posts/${data.data.id}`
+ case 'fanbox':
+ return `https://pixiv.net/fanbox/creator/${data.data.user_id}/post/${data.data.id}`
+ case 'dlsite':
+ return `https://dlsite.com/home/work/=/${data.data.id}`
+ default:
+ // throw new errors_1.SagiriClientError(999, `Unknown service type for Kemono: ${data.data.service}`)
+ logger.error(999, `Unknown service type for Kemono: ${data.data.service}`)
+ }
+ },
+ authorData: (data) => {
+ switch (data.service) {
+ case 'fantia':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://fantia.jp/fanclubs/${data.user_id}`
+ }
+ case 'subscribestar':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://subscribestar.adult/${data.user_id}`
+ }
+ case 'gumroad':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://gumroad.com/${data.user_id}`
+ }
+ case 'patreon':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://patreon.com/user?u=${data.user_id}`
+ }
+ case 'fanbox':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://pixiv.net/fanbox/creator/${data.user_id}`
+ }
+ case 'dlsite':
+ return {
+ authorName: data.user_name,
+ authorUrl: `https://dlsite.com/eng/cicrle/profile/=/marker_id/${data.user_id}`
+ }
+ default:
+ // throw new errors_1.SagiriClientError(999, `Unknown service type for Kemono: ${data.service}`)
+ logger.error(999, `Unknown service type for Kemono: ${data.service}`)
+ }
+ }
+}
+const Skeb = {
+ name: 'Skeb',
+ index: 44,
+ urlMatcher: /(?:(?:https?:\/\/)?skeb\.jp\/@\w+\/works\/\d+)/i,
+ backupUrl: (data) => `https://skeb.jp${data.data.path}`,
+ authorData: (data) => ({
+ authorName: data.creator_name,
+ authorUrl: data.author_url
+ })
+}
+// #endregion
+const sites = {
+ 3: DoujinMangaLexicon,
+ 4: DoujinMangaLexicon,
+ 5: Pixiv,
+ 6: Pixiv,
+ 8: NicoNicoSeiga,
+ 9: Danbooru,
+ 10: Drawr,
+ 11: Nijie,
+ 12: Yandere,
+ 13: OpeningsMoe,
+ 16: Fakku,
+ 18: NHentai,
+ 19: TwoDMarket,
+ 20: MediBang,
+ 21: AniDB,
+ 22: AniDB,
+ 23: IMDb,
+ 24: IMDb,
+ 25: Gelbooru,
+ 26: Konachan,
+ 27: SankakuChannel,
+ 28: AnimePictures,
+ 29: E621,
+ 30: IdolComplex,
+ 31: bcyIllust,
+ 32: bcyCosplay,
+ 33: PortalGraphics,
+ 34: DeviantArt,
+ 35: Pawoo,
+ 36: MangaUpdates,
+ 37: MangaDex,
+ 371: MangaDex,
+ // 38
+ 39: ArtStation,
+ 40: FurAffinity,
+ 41: Twitter,
+ 42: FurryNetwork,
+ 43: Kemono,
+ 44: Skeb
+}
+const resolveResult = item => {
+ const { data, header } = item
+ const id = header.index_id
+ if (!sites[id]) {
+ throw new Error(`Cannot resolve data for unknown index ${id}`)
+ }
+ const { name, urlMatcher, backupUrl, authorData } = sites[id]
+ let url
+ if (data.ext_urls && data.ext_urls.length > 1) {
+ url = data.ext_urls.filter((url) => urlMatcher.test(url))
+ } else if (data.ext_urls) {
+ url = data.ext_urls
+ }
+ if (!url) url = backupUrl(item)
+ const author = authorData?.(item.data) ?? { authorName: null, authorUrl: null }
+ return { id, url, name, ...author }
+ // return Object.assign({
+ // id,
+ // url,
+ // name
+ // }, ((_a = authorData === null || authorData === void 0 ? void 0 : authorData(item.data)) !== null && _a !== void 0 ? _a : { authorName: null, authorUrl: null }))
+}
+
+const sagiri = (response) => {
+ const unknownIds = new Set(response.results.filter((result) => !sites[result.header.index_id]).map((result) => result.header.index_id))
+ const results = response.results
+ .filter((result) => !unknownIds.has(result.header.index_id))
+ .sort((a, b) => b.header.similarity - a.header.similarity)
+
+ return results.map((result) => {
+ const { url, name, id, authorName, authorUrl } = resolveResult(result)
+ const { header: { similarity, thumbnail } } = result
+ return {
+ url,
+ site: name,
+ index: id,
+ similarity: Number(similarity),
+ thumbnail,
+ authorName,
+ authorUrl,
+ raw: result
+ }
+ })
+}
+export default sagiri
+// # sourceMappingURL=sites.js.map
diff --git a/Yunzai/plugins/yenai-plugin/tools/uploadRecord.js b/Yunzai/plugins/yenai-plugin/tools/uploadRecord.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ffc591039af49e5c3b978f8d9e0e1fc883ad499
--- /dev/null
+++ b/Yunzai/plugins/yenai-plugin/tools/uploadRecord.js
@@ -0,0 +1,291 @@
+/* eslint-disable no-void */
+import querystring from 'querystring'
+import fetch from 'node-fetch'
+import fs from 'fs'
+import path from 'path'
+import os from 'os'
+import crypto from 'crypto'
+import child_process from 'child_process'
+let errors = {}
+let core = null
+let Contactable = null
+
+try {
+ Contactable = (await import('oicq')).default
+ core = (await import('oicq')).core
+} catch (error) {
+ Contactable = (await import('icqq').catch(() => {}))?.default
+ core = (await import('icqq').catch(() => {}))?.core
+}
+
+async function uploadRecord (record_url, seconds = 0, transcoding = true) {
+ if (!Contactable) return segment.record(record_url)
+ const result = await getPttBuffer(record_url, Bot.config.ffmpeg_path, transcoding)
+ if (!result.buffer) {
+ return false
+ }
+ let buf = result.buffer
+ if (seconds == 0 && result.time) seconds = result.time.seconds
+ const hash = (0, md5)(buf)
+ const codec = String(buf.slice(0, 7)).includes('SILK') ? (transcoding ? 1 : 0) : 0
+ const body = core.pb.encode({
+ 1: 3,
+ 2: 3,
+ 5: {
+ 1: Contactable.target,
+ 2: Bot.uin,
+ 3: 0,
+ 4: hash,
+ 5: buf.length,
+ 6: hash,
+ 7: 5,
+ 8: 9,
+ 9: 4,
+ 11: 0,
+ 10: Bot.apk.version,
+ 12: 1,
+ 13: 1,
+ 14: codec,
+ 15: 1
+ }
+ })
+ const payload = await Bot.sendUni('PttStore.GroupPttUp', body)
+ const rsp = core.pb.decode(payload)[5]
+ rsp[2] && (0, errors.drop)(rsp[2], rsp[3])
+ const ip = rsp[5]?.[0] || rsp[5]; const port = rsp[6]?.[0] || rsp[6]
+ const ukey = rsp[7].toHex(); const filekey = rsp[11].toHex()
+ const params = {
+ ver: 4679,
+ ukey,
+ filekey,
+ filesize: buf.length,
+ bmd5: hash.toString('hex'),
+ mType: 'pttDu',
+ voice_encodec: codec
+ }
+ const url = `http://${(0, int32ip2str)(ip)}:${port}/?` + querystring.stringify(params)
+ const headers = {
+ 'User-Agent': `QQ/${Bot.apk.version} CFNetwork/1126`,
+ 'Net-Type': 'Wifi'
+ }
+ await fetch(url, {
+ method: 'POST', // post请求
+ headers,
+ body: buf
+ })
+ // await axios.post(url, buf, { headers });
+
+ const fid = rsp[11].toBuffer()
+ const b = core.pb.encode({
+ 1: 4,
+ 2: Bot.uin,
+ 3: fid,
+ 4: hash,
+ 5: hash.toString('hex') + '.amr',
+ 6: seconds,
+ 11: 1,
+ 18: fid,
+ 19: seconds,
+ 30: Buffer.from([8, 0, 40, 0, 56, 0])
+ })
+ return {
+ type: 'record', file: 'protobuf://' + Buffer.from(b).toString('base64')
+ }
+}
+
+export default uploadRecord
+
+async function getPttBuffer (file, ffmpeg = 'ffmpeg', transcoding = true) {
+ let buffer
+ let time
+ if (file instanceof Buffer || file.startsWith('base64://')) {
+ // Buffer或base64
+ const buf = file instanceof Buffer ? file : Buffer.from(file.slice(9), 'base64')
+ const head = buf.slice(0, 7).toString()
+ if (head.includes('SILK') || head.includes('AMR') || !transcoding) {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)())
+ await fs.promises.writeFile(tmpfile, buf)
+ let result = await getAudioTime(tmpfile, ffmpeg)
+ if (result.code == 1) time = result.data
+ fs.unlink(tmpfile, NOOP)
+ buffer = buf
+ } else {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)())
+ let result = await getAudioTime(tmpfile, ffmpeg)
+ if (result.code == 1) time = result.data
+ await fs.promises.writeFile(tmpfile, buf)
+ buffer = await audioTrans(tmpfile, ffmpeg)
+ }
+ } else if (file.startsWith('http://') || file.startsWith('https://')) {
+ // 网络文件
+ // const readable = (await axios.get(file, { responseType: "stream" })).data;
+ try {
+ const headers = {
+ 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 12; MI 9 Build/SKQ1.211230.001)'
+ }
+ let response = await fetch(file, {
+ method: 'GET', // post请求
+ headers
+ })
+ const buf = Buffer.from(await response.arrayBuffer())
+ const tmpfile = path.join(TMP_DIR, (0, uuid)())
+ await fs.promises.writeFile(tmpfile, buf)
+ // await (0, pipeline)(readable.pipe(new DownloadTransform), fs.createWriteStream(tmpfile));
+ const head = await read7Bytes(tmpfile)
+ let result = await getAudioTime(tmpfile, ffmpeg)
+ if (result.code == 1) time = result.data
+ if (head.includes('SILK') || head.includes('AMR') || !transcoding) {
+ // const buf = await fs.promises.readFile(tmpfile);
+ fs.unlink(tmpfile, NOOP)
+ buffer = buf
+ } else {
+ buffer = await audioTrans(tmpfile, ffmpeg)
+ }
+ } catch (err) {}
+ } else {
+ // 本地文件
+ file = String(file).replace(/^file:\/{2}/, '')
+ IS_WIN && file.startsWith('/') && (file = file.slice(1))
+ const head = await read7Bytes(file)
+ let result = await getAudioTime(file, ffmpeg)
+ if (result.code == 1) time = result.data
+ if (head.includes('SILK') || head.includes('AMR') || !transcoding) {
+ buffer = await fs.promises.readFile(file)
+ } else {
+ buffer = await audioTrans(file, ffmpeg)
+ }
+ }
+ return { buffer, time }
+}
+
+async function getAudioTime (file, ffmpeg = 'ffmpeg') {
+ return new Promise((resolve, _reject) => {
+ (0, child_process.exec)(`${ffmpeg} -i "${file}"`, async (_error, _stdout, stderr) => {
+ try {
+ let time = stderr.split('Duration:')[1]?.split(',')[0].trim()
+ let arr = time?.split(':')
+ arr.reverse()
+ let n = 1
+ let s = 0
+ for (let val of arr) {
+ if (parseInt(val) > 0) s += parseInt(val) * n
+ n *= 60
+ }
+ resolve({
+ code: 1,
+ data: {
+ time,
+ seconds: s,
+ exec_text: stderr
+ }
+ })
+ } catch {
+ resolve({ code: -1 })
+ }
+ })
+ })
+}
+
+async function audioTrans (file, ffmpeg = 'ffmpeg') {
+ return new Promise((resolve, reject) => {
+ const tmpfile = path.join(TMP_DIR, (0, uuid)());
+ (0, child_process.exec)(`${ffmpeg} -y -i "${file}" -ac 1 -ar 8000 -f amr "${tmpfile}"`, async (_error, _stdout, _stderr) => {
+ try {
+ const amr = await fs.promises.readFile(tmpfile)
+ resolve(amr)
+ } catch {
+ reject(new core.ApiRejection(errors.ErrorCode.FFmpegPttTransError, '音频转码到amr失败,请确认你的ffmpeg可以处理此转换'))
+ } finally {
+ fs.unlink(tmpfile, NOOP)
+ }
+ })
+ })
+}
+
+async function read7Bytes (file) {
+ const fd = await fs.promises.open(file, 'r')
+ const buf = (await fd.read(Buffer.alloc(7), 0, 7, 0)).buffer
+ fd.close()
+ return buf
+}
+
+function uuid () {
+ let hex = crypto.randomBytes(16).toString('hex')
+ return hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20)
+}
+
+function int32ip2str (ip) {
+ if (typeof ip === 'string') { return ip }
+ ip = ip & 0xffffffff
+ return [
+ ip & 0xff,
+ (ip & 0xff00) >> 8,
+ (ip & 0xff0000) >> 16,
+ (ip & 0xff000000) >> 24 & 0xff
+ ].join('.')
+}
+
+const IS_WIN = os.platform() === 'win32'
+/** 系统临时目录,用于临时存放下载的图片等内容 */
+const TMP_DIR = os.tmpdir()
+
+/** no operation */
+const NOOP = () => { }
+
+/** md5 hash */
+const md5 = (data) => (0, crypto.createHash)('md5').update(data).digest()
+
+errors.LoginErrorCode = errors.drop = errors.ErrorCode = void 0
+let ErrorCode;
+(function (ErrorCode) {
+ /** 客户端离线 */
+ ErrorCode[ErrorCode.ClientNotOnline = -1] = 'ClientNotOnline'
+ /** 发包超时未收到服务器回应 */
+ ErrorCode[ErrorCode.PacketTimeout = -2] = 'PacketTimeout'
+ /** 用户不存在 */
+ ErrorCode[ErrorCode.UserNotExists = -10] = 'UserNotExists'
+ /** 群不存在(未加入) */
+ ErrorCode[ErrorCode.GroupNotJoined = -20] = 'GroupNotJoined'
+ /** 群员不存在 */
+ ErrorCode[ErrorCode.MemberNotExists = -30] = 'MemberNotExists'
+ /** 发消息时传入的参数不正确 */
+ ErrorCode[ErrorCode.MessageBuilderError = -60] = 'MessageBuilderError'
+ /** 群消息被风控发送失败 */
+ ErrorCode[ErrorCode.RiskMessageError = -70] = 'RiskMessageError'
+ /** 群消息有敏感词发送失败 */
+ ErrorCode[ErrorCode.SensitiveWordsError = -80] = 'SensitiveWordsError'
+ /** 上传图片/文件/视频等数据超时 */
+ ErrorCode[ErrorCode.HighwayTimeout = -110] = 'HighwayTimeout'
+ /** 上传图片/文件/视频等数据遇到网络错误 */
+ ErrorCode[ErrorCode.HighwayNetworkError = -120] = 'HighwayNetworkError'
+ /** 没有上传通道 */
+ ErrorCode[ErrorCode.NoUploadChannel = -130] = 'NoUploadChannel'
+ /** 不支持的file类型(没有流) */
+ ErrorCode[ErrorCode.HighwayFileTypeError = -140] = 'HighwayFileTypeError'
+ /** 文件安全校验未通过不存在 */
+ ErrorCode[ErrorCode.UnsafeFile = -150] = 'UnsafeFile'
+ /** 离线(私聊)文件不存在 */
+ ErrorCode[ErrorCode.OfflineFileNotExists = -160] = 'OfflineFileNotExists'
+ /** 群文件不存在(无法转发) */
+ ErrorCode[ErrorCode.GroupFileNotExists = -170] = 'GroupFileNotExists'
+ /** 获取视频中的图片失败 */
+ ErrorCode[ErrorCode.FFmpegVideoThumbError = -210] = 'FFmpegVideoThumbError'
+ /** 音频转换失败 */
+ ErrorCode[ErrorCode.FFmpegPttTransError = -220] = 'FFmpegPttTransError'
+})(ErrorCode = errors.ErrorCode || (errors.ErrorCode = {}))
+const ErrorMessage = {
+ [ErrorCode.UserNotExists]: '查无此人',
+ [ErrorCode.GroupNotJoined]: '未加入的群',
+ [ErrorCode.MemberNotExists]: '幽灵群员',
+ [ErrorCode.RiskMessageError]: '群消息发送失败,可能被风控',
+ [ErrorCode.SensitiveWordsError]: '群消息发送失败,请检查消息内容',
+ 10: '消息过长',
+ 34: '消息过长',
+ 120: '在该群被禁言',
+ 121: 'AT全体剩余次数不足'
+}
+function drop (code, message) {
+ if (!message || !message.length) { message = ErrorMessage[code] }
+ throw new core.ApiRejection(code, message)
+}
+errors.drop = drop