Upload 44 files
Browse files- Yunzai/.gitignore +0 -1
- Yunzai/.npmrc +3 -1
- Yunzai/CHANGELOG.md +16 -0
- Yunzai/README.md +19 -3
- Yunzai/lib/bot.js +157 -41
- Yunzai/lib/config/config.js +8 -6
- Yunzai/lib/config/init.js +25 -18
- Yunzai/lib/config/redis.js +1 -0
- Yunzai/lib/events/connect.js +2 -2
- Yunzai/lib/events/online.js +2 -2
- Yunzai/lib/modules/oicq/index.js +14 -13
- Yunzai/lib/plugins/loader.js +20 -20
- Yunzai/lib/plugins/plugin.js +9 -0
- Yunzai/lib/plugins/runtime.js +6 -3
- Yunzai/lib/plugins/stdin.js +12 -37
- Yunzai/lib/tools/log.js +34 -0
- Yunzai/package-lock.json +0 -0
- Yunzai/package.json +12 -13
- Yunzai/pnpm-lock.yaml +0 -0
Yunzai/.gitignore
CHANGED
|
@@ -137,7 +137,6 @@ config/test/*
|
|
| 137 |
data/
|
| 138 |
!config/test/default.yaml
|
| 139 |
logs/
|
| 140 |
-
resources/
|
| 141 |
|
| 142 |
# Docker file
|
| 143 |
redis
|
|
|
|
| 137 |
data/
|
| 138 |
!config/test/default.yaml
|
| 139 |
logs/
|
|
|
|
| 140 |
|
| 141 |
# Docker file
|
| 142 |
redis
|
Yunzai/.npmrc
CHANGED
|
@@ -1,3 +1,5 @@
|
|
| 1 |
registry=https://registry.npmmirror.com
|
| 2 |
node_sqlite3_binary_host_mirror=https://npmmirror.com/mirrors/sqlite3
|
| 3 |
-
canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas
|
|
|
|
|
|
|
|
|
| 1 |
registry=https://registry.npmmirror.com
|
| 2 |
node_sqlite3_binary_host_mirror=https://npmmirror.com/mirrors/sqlite3
|
| 3 |
+
canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas
|
| 4 |
+
sharp_binary_host=https://npmmirror.com/mirrors/sharp
|
| 5 |
+
sharp_libvips_binary_host=https://npmmirror.com/mirrors/sharp-libvips
|
Yunzai/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# 3.1.1
|
| 2 |
|
| 3 |
* 支持协议端:米游社大别野Bot
|
|
|
|
| 1 |
+
# 3.1.3
|
| 2 |
+
|
| 3 |
+
* 支持协议端:QQBot
|
| 4 |
+
* **请注意:**
|
| 5 |
+
* 从3.1.3版本开始,原genshin包内的功能会逐步重构,与miao-plugin进行整合,以降低后续游戏版本升级时的维护成本
|
| 6 |
+
* 在整合过程中,可能会移除一些重复或迁移成本较高的功能,以及可能会有功能不稳定情况
|
| 7 |
+
* 如介意,请切换至**v312-backup**分支
|
| 8 |
+
|
| 9 |
+
# 3.1.2
|
| 10 |
+
|
| 11 |
+
* 支持协议端:OPQBot
|
| 12 |
+
* 新增`#绑定用户`命令
|
| 13 |
+
* 可将其他QQ绑定至当前用户,以打通多个用户,子用户使用主用户的CK与UID等信息
|
| 14 |
+
* 同时也可绑定其他平台的用户,例如频道、微信等。如需链接至其他平台需使用TRSS-Yunzai或Lain-plugin
|
| 15 |
+
* 部分命令可能无法识别绑定后的主用户,如遇问题可反馈
|
| 16 |
+
|
| 17 |
# 3.1.1
|
| 18 |
|
| 19 |
* 支持协议端:米游社大别野Bot
|
Yunzai/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
# TRSS-Yunzai
|
| 4 |
|
| 5 |
-
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、GSUIDCore、ICQQ、QQ频道、微信、KOOK、Telegram、Discord
|
| 6 |
|
| 7 |
[](https://github.com/TimeRainStarSky/Yunzai)
|
| 8 |
[](../../stargazers)
|
|
@@ -118,6 +118,12 @@ ws://localhost:2536/GSUIDCore
|
|
| 118 |
|
| 119 |
</details>
|
| 120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
<details><summary>QQ频道</summary>
|
| 122 |
|
| 123 |
[TRSS-Yunzai QQGuild Plugin](../../../Yunzai-QQGuild-Plugin)
|
|
@@ -154,9 +160,19 @@ ws://localhost:2536/GSUIDCore
|
|
| 154 |
|
| 155 |
</details>
|
| 156 |
|
| 157 |
-
<details><summary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
|
| 159 |
-
[TRSS-Yunzai
|
| 160 |
|
| 161 |
</details>
|
| 162 |
|
|
|
|
| 2 |
|
| 3 |
# TRSS-Yunzai
|
| 4 |
|
| 5 |
+
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、GSUIDCore、ICQQ、QQBot、QQ频道、微信、KOOK、Telegram、Discord、OPQBot
|
| 6 |
|
| 7 |
[](https://github.com/TimeRainStarSky/Yunzai)
|
| 8 |
[](../../stargazers)
|
|
|
|
| 118 |
|
| 119 |
</details>
|
| 120 |
|
| 121 |
+
<details><summary>QQBot</summary>
|
| 122 |
+
|
| 123 |
+
[TRSS-Yunzai QQBot Plugin](../../../Yunzai-QQBot-Plugin)
|
| 124 |
+
|
| 125 |
+
</details>
|
| 126 |
+
|
| 127 |
<details><summary>QQ频道</summary>
|
| 128 |
|
| 129 |
[TRSS-Yunzai QQGuild Plugin](../../../Yunzai-QQGuild-Plugin)
|
|
|
|
| 160 |
|
| 161 |
</details>
|
| 162 |
|
| 163 |
+
<details><summary>OPQBot</summary>
|
| 164 |
+
|
| 165 |
+
下载运行 [OPQBot](https://opqbot.com),启动参数添加:
|
| 166 |
+
|
| 167 |
+
```
|
| 168 |
+
-wsserver ws://localhost:2536/OPQBot
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
</details>
|
| 172 |
+
|
| 173 |
+
<details><summary>路由</summary>
|
| 174 |
|
| 175 |
+
[TRSS-Yunzai Route Plugin](../../../Yunzai-Route-Plugin)
|
| 176 |
|
| 177 |
</details>
|
| 178 |
|
Yunzai/lib/bot.js
CHANGED
|
@@ -7,48 +7,61 @@ import express from "express"
|
|
| 7 |
import http from "http"
|
| 8 |
import { WebSocketServer } from "ws"
|
| 9 |
import _ from "lodash"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
export default class Yunzai extends EventEmitter {
|
| 12 |
constructor() {
|
| 13 |
super()
|
| 14 |
this.uin = []
|
| 15 |
this.adapter = []
|
|
|
|
| 16 |
this.express = express()
|
| 17 |
this.server = http.createServer(this.express)
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
conn.id = `${req.connection.remoteAddress}-${req.headers["sec-websocket-key"]}`
|
| 21 |
-
this.makeLog("mark", `${logger.blue(`[${conn.id} <=> ${req.url}]`)} 建立连接:${JSON.stringify(req.headers)}`)
|
| 22 |
-
conn.on("error", logger.error)
|
| 23 |
-
conn.on("close", () => this.makeLog("mark", `${logger.blue(`[${conn.id} <≠> ${req.url}]`)} 断开连接`))
|
| 24 |
-
conn.on("message", msg => this.makeLog("debug", `${logger.blue(`[${conn.id} => ${req.url}]`)} 消息:${String(msg).trim()}`))
|
| 25 |
-
conn.sendMsg = msg => {
|
| 26 |
-
if (typeof msg == "object")
|
| 27 |
-
msg = JSON.stringify(msg)
|
| 28 |
-
this.makeLog("debug", `${logger.blue(`[${conn.id} <= ${req.url}]`)} 消息:${msg}`)
|
| 29 |
-
return conn.send(msg)
|
| 30 |
-
}
|
| 31 |
-
for (const i of this.wsf[req.url.split("/")[1]] || [])
|
| 32 |
-
i(conn, req, socket, head)
|
| 33 |
-
})
|
| 34 |
-
})
|
| 35 |
this.wss = new WebSocketServer({ noServer: true })
|
| 36 |
this.wsf = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
}
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
}
|
| 42 |
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
| 52 |
}
|
| 53 |
|
| 54 |
async run() {
|
|
@@ -59,21 +72,124 @@ export default class Yunzai extends EventEmitter {
|
|
| 59 |
this.emit("online", this)
|
| 60 |
}
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
|
| 66 |
-
})
|
| 67 |
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
})
|
| 75 |
}
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
getFriendArray() {
|
| 78 |
const array = []
|
| 79 |
for (const bot_id of this.uin)
|
|
@@ -185,7 +301,7 @@ export default class Yunzai extends EventEmitter {
|
|
| 185 |
return false
|
| 186 |
}
|
| 187 |
|
| 188 |
-
async
|
| 189 |
if (typeof fnc != "function") {
|
| 190 |
const { self_id, user_id } = fnc
|
| 191 |
fnc = data => data.self_id == self_id && data.user_id == user_id
|
|
@@ -210,7 +326,7 @@ export default class Yunzai extends EventEmitter {
|
|
| 210 |
}
|
| 211 |
|
| 212 |
getMasterMsg() {
|
| 213 |
-
return this.
|
| 214 |
cfg.master[data.self_id]?.includes(String(data.user_id)))
|
| 215 |
}
|
| 216 |
|
|
|
|
| 7 |
import http from "http"
|
| 8 |
import { WebSocketServer } from "ws"
|
| 9 |
import _ from "lodash"
|
| 10 |
+
import fs from "node:fs"
|
| 11 |
+
import fetch from "node-fetch"
|
| 12 |
+
import { randomUUID } from "node:crypto"
|
| 13 |
+
import { exec } from "child_process"
|
| 14 |
+
import { fileTypeFromBuffer } from "file-type"
|
| 15 |
+
import md5 from "md5"
|
| 16 |
|
| 17 |
export default class Yunzai extends EventEmitter {
|
| 18 |
constructor() {
|
| 19 |
super()
|
| 20 |
this.uin = []
|
| 21 |
this.adapter = []
|
| 22 |
+
|
| 23 |
this.express = express()
|
| 24 |
this.server = http.createServer(this.express)
|
| 25 |
+
|
| 26 |
+
this.server.on("upgrade", (...args) => this.wsConnect(...args))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
this.wss = new WebSocketServer({ noServer: true })
|
| 28 |
this.wsf = {}
|
| 29 |
+
|
| 30 |
+
this.fs = {}
|
| 31 |
+
this.express.use("/File", (...args) => this.fileSend(...args))
|
| 32 |
+
this.fileToUrl("resources/http/File/404.jpg", { name: 404, time: 0 })
|
| 33 |
+
this.fileToUrl("resources/http/File/timeout.jpg", { name: "timeout", time: 0 })
|
| 34 |
}
|
| 35 |
|
| 36 |
+
wsConnect(req, socket, head) {
|
| 37 |
+
this.wss.handleUpgrade(req, socket, head, conn => {
|
| 38 |
+
conn.id = `${req.connection.remoteAddress}-${req.headers["sec-websocket-key"]}`
|
| 39 |
+
this.makeLog("mark", `${logger.blue(`[${conn.id} <=> ws://${req.headers.host}${req.url}]`)} 建立连接:${JSON.stringify(req.headers)}`)
|
| 40 |
+
conn.on("error", logger.error)
|
| 41 |
+
conn.on("close", () => this.makeLog("mark", `${logger.blue(`[${conn.id} <≠> ws://${req.headers.host}${req.url}]`)} 断开连接`))
|
| 42 |
+
conn.on("message", msg => this.makeLog("debug", `${logger.blue(`[${conn.id} => ws://${req.headers.host}${req.url}]`)} 消息:${String(msg).trim()}`))
|
| 43 |
+
conn.sendMsg = msg => {
|
| 44 |
+
if (!Buffer.isBuffer(msg)) msg = this.String(msg)
|
| 45 |
+
this.makeLog("debug", `${logger.blue(`[${conn.id} <= ws://${req.headers.host}${req.url}]`)} 消息:${msg}`)
|
| 46 |
+
return conn.send(msg)
|
| 47 |
+
}
|
| 48 |
+
for (const i of this.wsf[req.url.split("/")[1]] || [])
|
| 49 |
+
i(conn, req, socket, head)
|
| 50 |
+
})
|
| 51 |
}
|
| 52 |
|
| 53 |
+
serverLoad() {
|
| 54 |
+
this.express.use(req => {
|
| 55 |
+
logger.mark(`${logger.blue(`[${req.ip} => http://${req.headers.host}${req.url}]`)} HTTP ${req.method} 请求:${JSON.stringify(req.headers)}`)
|
| 56 |
+
req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
|
| 57 |
+
})
|
| 58 |
+
|
| 59 |
+
this.server.listen(cfg.bot.port, () => {
|
| 60 |
+
logger.mark(`启动 HTTP 服务器:${logger.green(`http://[${this.server.address().address}]:${this.server.address().port}`)}`)
|
| 61 |
+
const url = cfg.bot.url.replace(/^http/, "ws")
|
| 62 |
+
for (const i of Object.keys(this.wsf))
|
| 63 |
+
logger.info(`${i} 连接地址:${logger.blue(`${url}/${i}`)}`)
|
| 64 |
+
})
|
| 65 |
}
|
| 66 |
|
| 67 |
async run() {
|
|
|
|
| 72 |
this.emit("online", this)
|
| 73 |
}
|
| 74 |
|
| 75 |
+
sleep(time) {
|
| 76 |
+
return new Promise(resolve => setTimeout(resolve, time))
|
| 77 |
+
}
|
|
|
|
|
|
|
| 78 |
|
| 79 |
+
String(data) {
|
| 80 |
+
switch (typeof data) {
|
| 81 |
+
case "string":
|
| 82 |
+
return data
|
| 83 |
+
case "object":
|
| 84 |
+
return JSON.stringify(data)
|
| 85 |
+
}
|
| 86 |
+
return String(data)
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
Buffer(data, opts = {}) {
|
| 90 |
+
if (Buffer.isBuffer(data)) return data
|
| 91 |
+
data = this.String(data)
|
| 92 |
+
|
| 93 |
+
if (data.match(/^base64:\/\//)) {
|
| 94 |
+
return Buffer.from(data.replace(/^base64:\/\//, ""), "base64")
|
| 95 |
+
} else if (data.match(/^https?:\/\//)) {
|
| 96 |
+
if (opts.http) return data
|
| 97 |
+
return (async () => Buffer.from(await (await fetch(data)).arrayBuffer()))()
|
| 98 |
+
} else if (fs.existsSync(data.replace(/^file:\/\//, ""))) {
|
| 99 |
+
if (opts.file) return data
|
| 100 |
+
return Buffer.from(fs.readFileSync(data.replace(/^file:\/\//, "")))
|
| 101 |
+
}
|
| 102 |
+
return data
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
async fileType(data, name) {
|
| 106 |
+
const file = {}
|
| 107 |
+
try {
|
| 108 |
+
if (Buffer.isBuffer(data)) {
|
| 109 |
+
file.url = name || "Buffer"
|
| 110 |
+
file.buffer = data
|
| 111 |
+
} else {
|
| 112 |
+
file.url = data.replace(/^base64:\/\/.*/, "base64://...")
|
| 113 |
+
file.buffer = await this.Buffer(data)
|
| 114 |
+
}
|
| 115 |
+
if (Buffer.isBuffer(file.buffer)) {
|
| 116 |
+
file.type = await fileTypeFromBuffer(file.buffer)
|
| 117 |
+
file.md5 = md5(file.buffer)
|
| 118 |
+
file.name = name || `${Date.now()}.${file.md5.slice(0,8)}.${file.type.ext}`
|
| 119 |
+
} else {
|
| 120 |
+
file.name = name || `${Date.now()}-path.basename(file.buffer)`
|
| 121 |
+
}
|
| 122 |
+
} catch (err) {
|
| 123 |
+
logger.error(`文件类型检测错误:${logger.red(err)}`)
|
| 124 |
+
}
|
| 125 |
+
return file
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
async fileToUrl(file, opts = {}) {
|
| 129 |
+
const { name, time = 60000, times } = opts
|
| 130 |
+
|
| 131 |
+
file = await this.fileType(file, name)
|
| 132 |
+
if (!Buffer.isBuffer(file.buffer)) return file.buffer
|
| 133 |
+
if (!file.name) file.name = randomUUID()
|
| 134 |
+
|
| 135 |
+
if (typeof times == "number") file.times = times
|
| 136 |
+
this.fs[file.name] = file
|
| 137 |
+
if (time) setTimeout(() => this.fs[file.name] = this.fs.timeout, time)
|
| 138 |
+
return `${cfg.bot.url}/File/${file.name}`
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
fileSend(req) {
|
| 142 |
+
const url = req.url.replace(/^\//, "")
|
| 143 |
+
let file = this.fs[url]
|
| 144 |
+
if (!file) file = this.fs[404]
|
| 145 |
+
|
| 146 |
+
if (typeof file.times == "number") {
|
| 147 |
+
if (file.times > 0) file.times = file.times-1
|
| 148 |
+
else file = this.fs.timeout
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
if (file.type?.mime)
|
| 152 |
+
req.res.setHeader("Content-Type", file.type.mime)
|
| 153 |
+
|
| 154 |
+
logger.mark(`${logger.blue(`[${req.ip} => http://${req.headers.host}/File/${url}]`)} HTTP ${req.method} 请求:${JSON.stringify(req.headers)}`)
|
| 155 |
+
logger.mark(`${logger.blue(`[${req.ip} <= http://${req.headers.host}/File/${url}]`)} 发送文件:${file.name}(${file.url} ${(file.buffer.length/1024).toFixed(2)}KB)`)
|
| 156 |
+
req.res.send(file.buffer)
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
async exec(cmd) {
|
| 160 |
+
return new Promise(resolve => {
|
| 161 |
+
this.makeLog("mark", `[命令执行开始] ${logger.blue(cmd)}`)
|
| 162 |
+
exec(cmd, (error, stdout, stderr) => {
|
| 163 |
+
this.makeLog("mark", `[命令执行完成] ${logger.blue(cmd)}${stdout?`\n${this.String(stdout).trim()}`:""}${stderr?logger.red(`\n${this.String(stderr).trim()}`):""}`)
|
| 164 |
+
if (error) this.makeLog("mark", `[命令执行错误] ${logger.blue(cmd)}\n${logger.red(this.String(error).trim())}`)
|
| 165 |
+
resolve({ error, stdout, stderr })
|
| 166 |
+
})
|
| 167 |
})
|
| 168 |
}
|
| 169 |
|
| 170 |
+
makeLog(level, msg, id) {
|
| 171 |
+
const log = []
|
| 172 |
+
if (id) log.push(logger.blue(`[${id}]`))
|
| 173 |
+
for (const i of Array.isArray(msg) ? msg : [msg]) {
|
| 174 |
+
if (i?.replace)
|
| 175 |
+
log.push(_.truncate(i.replace(/{"type":"Buffer","data":\[.*?\]}/g, "(Buffer)"), { length: cfg.bot.log_length }))
|
| 176 |
+
else
|
| 177 |
+
log.push(i)
|
| 178 |
+
}
|
| 179 |
+
logger[level](...log)
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
em(name = "", data = {}) {
|
| 183 |
+
if (data.self_id)
|
| 184 |
+
Object.defineProperty(data, "bot", { value: Bot[data.self_id] })
|
| 185 |
+
while (true) {
|
| 186 |
+
this.emit(name, data)
|
| 187 |
+
const i = name.lastIndexOf(".")
|
| 188 |
+
if (i == -1) break
|
| 189 |
+
name = name.slice(0, i)
|
| 190 |
+
}
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
getFriendArray() {
|
| 194 |
const array = []
|
| 195 |
for (const bot_id of this.uin)
|
|
|
|
| 301 |
return false
|
| 302 |
}
|
| 303 |
|
| 304 |
+
async getTextMsg(fnc = () => true) {
|
| 305 |
if (typeof fnc != "function") {
|
| 306 |
const { self_id, user_id } = fnc
|
| 307 |
fnc = data => data.self_id == self_id && data.user_id == user_id
|
|
|
|
| 326 |
}
|
| 327 |
|
| 328 |
getMasterMsg() {
|
| 329 |
+
return this.getTextMsg(data =>
|
| 330 |
cfg.master[data.self_id]?.includes(String(data.user_id)))
|
| 331 |
}
|
| 332 |
|
Yunzai/lib/config/config.js
CHANGED
|
@@ -18,11 +18,11 @@ class Cfg {
|
|
| 18 |
let path = "config/config/"
|
| 19 |
let pathDef = "config/default_config/"
|
| 20 |
const files = fs.readdirSync(pathDef).filter(file => file.endsWith(".yaml"))
|
| 21 |
-
for (
|
| 22 |
if (!fs.existsSync(`${path}${file}`))
|
| 23 |
fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
|
| 24 |
-
|
| 25 |
-
|
| 26 |
}
|
| 27 |
|
| 28 |
/** Bot配置 */
|
|
@@ -69,10 +69,12 @@ class Cfg {
|
|
| 69 |
const masters = {}
|
| 70 |
for (let i of master) {
|
| 71 |
i = i.split(":")
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
| 74 |
else
|
| 75 |
-
masters[
|
| 76 |
}
|
| 77 |
return masters
|
| 78 |
}
|
|
|
|
| 18 |
let path = "config/config/"
|
| 19 |
let pathDef = "config/default_config/"
|
| 20 |
const files = fs.readdirSync(pathDef).filter(file => file.endsWith(".yaml"))
|
| 21 |
+
for (const file of files)
|
| 22 |
if (!fs.existsSync(`${path}${file}`))
|
| 23 |
fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
|
| 24 |
+
for (const i of ["data", "temp"])
|
| 25 |
+
if (!fs.existsSync(i)) fs.mkdirSync(i)
|
| 26 |
}
|
| 27 |
|
| 28 |
/** Bot配置 */
|
|
|
|
| 69 |
const masters = {}
|
| 70 |
for (let i of master) {
|
| 71 |
i = i.split(":")
|
| 72 |
+
const bot_id = i.shift()
|
| 73 |
+
const user_id = i.join(":")
|
| 74 |
+
if (Array.isArray(masters[bot_id]))
|
| 75 |
+
masters[bot_id].push(user_id)
|
| 76 |
else
|
| 77 |
+
masters[bot_id] = [user_id]
|
| 78 |
}
|
| 79 |
return masters
|
| 80 |
}
|
Yunzai/lib/config/init.js
CHANGED
|
@@ -1,28 +1,35 @@
|
|
| 1 |
-
import setLog from
|
| 2 |
-
import redisInit from
|
| 3 |
-
import { checkRun } from
|
| 4 |
-
import cfg from
|
| 5 |
|
| 6 |
/** 设置标题 */
|
| 7 |
-
process.title =
|
| 8 |
|
| 9 |
/** 设置时区 */
|
| 10 |
-
process.env.TZ =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
/** 捕获未处理的Promise错误 */
|
| 13 |
-
process.on(
|
| 14 |
-
if (logger)
|
| 15 |
-
|
| 16 |
-
} else {
|
| 17 |
-
console.log(error)
|
| 18 |
-
}
|
| 19 |
})
|
| 20 |
|
| 21 |
/** 退出事件 */
|
| 22 |
-
process.on(
|
| 23 |
-
if (typeof redis !=
|
| 24 |
await redis.save()
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
})
|
| 27 |
|
| 28 |
await checkInit()
|
|
@@ -32,11 +39,11 @@ async function checkInit() {
|
|
| 32 |
/** 日志设置 */
|
| 33 |
setLog()
|
| 34 |
|
| 35 |
-
logger.mark(
|
| 36 |
logger.mark(logger.yellow(`TRSS-Yunzai v${cfg.package.version} 启动中...`))
|
| 37 |
-
logger.mark(logger.cyan(
|
| 38 |
|
| 39 |
await redisInit()
|
| 40 |
|
| 41 |
checkRun()
|
| 42 |
-
}
|
|
|
|
| 1 |
+
import setLog from "./log.js"
|
| 2 |
+
import redisInit from "./redis.js"
|
| 3 |
+
import { checkRun } from "./check.js"
|
| 4 |
+
import cfg from "./config.js"
|
| 5 |
|
| 6 |
/** 设置标题 */
|
| 7 |
+
process.title = `TRSS Yunzai v${cfg.package.version} © 2023 - 2024 TimeRainStarSky`
|
| 8 |
|
| 9 |
/** 设置时区 */
|
| 10 |
+
process.env.TZ = "Asia/Shanghai"
|
| 11 |
+
|
| 12 |
+
/** 捕获未处理的错误 */
|
| 13 |
+
process.on("uncaughtException", error => {
|
| 14 |
+
if (typeof logger == "undefined") console.log(error)
|
| 15 |
+
else logger.error(error)
|
| 16 |
+
})
|
| 17 |
|
| 18 |
/** 捕获未处理的Promise错误 */
|
| 19 |
+
process.on("unhandledRejection", (error, promise) => {
|
| 20 |
+
if (typeof logger == "undefined") console.log(error)
|
| 21 |
+
else logger.error(error)
|
|
|
|
|
|
|
|
|
|
| 22 |
})
|
| 23 |
|
| 24 |
/** 退出事件 */
|
| 25 |
+
process.on("exit", async code => {
|
| 26 |
+
if (typeof redis != "undefined" && typeof test == "undefined")
|
| 27 |
await redis.save()
|
| 28 |
+
|
| 29 |
+
if (typeof logger == "undefined")
|
| 30 |
+
console.log("TRSS-Yunzai 已停止运行")
|
| 31 |
+
else
|
| 32 |
+
logger.mark(logger.magenta("TRSS-Yunzai 已停止运行"))
|
| 33 |
})
|
| 34 |
|
| 35 |
await checkInit()
|
|
|
|
| 39 |
/** 日志设置 */
|
| 40 |
setLog()
|
| 41 |
|
| 42 |
+
logger.mark("----^_^----")
|
| 43 |
logger.mark(logger.yellow(`TRSS-Yunzai v${cfg.package.version} 启动中...`))
|
| 44 |
+
logger.mark(logger.cyan("https://github.com/TimeRainStarSky/Yunzai"))
|
| 45 |
|
| 46 |
await redisInit()
|
| 47 |
|
| 48 |
checkRun()
|
| 49 |
+
}
|
Yunzai/lib/config/redis.js
CHANGED
|
@@ -44,6 +44,7 @@ export default async function redisInit() {
|
|
| 44 |
})
|
| 45 |
|
| 46 |
/** 全局变量 redis */
|
|
|
|
| 47 |
global.redis = client
|
| 48 |
logger.info("Redis 连接成功")
|
| 49 |
return client
|
|
|
|
| 44 |
})
|
| 45 |
|
| 46 |
/** 全局变量 redis */
|
| 47 |
+
client.url = redisUrl
|
| 48 |
global.redis = client
|
| 49 |
logger.info("Redis 连接成功")
|
| 50 |
return client
|
Yunzai/lib/events/connect.js
CHANGED
|
@@ -13,10 +13,10 @@ export default class connectEvent extends EventListener {
|
|
| 13 |
if (!Bot.uin.includes(e.self_id))
|
| 14 |
Bot.uin.push(e.self_id)
|
| 15 |
|
| 16 |
-
if (!cfg.bot.
|
| 17 |
const key = `Yz:loginMsg:${e.self_id}`
|
| 18 |
if (await redis.get(key)) return
|
| 19 |
-
redis.set(key, "1", { EX: cfg.bot.online_msg_exp })
|
| 20 |
for (const i of cfg.master[e.self_id] || [])
|
| 21 |
e.bot.pickFriend(i).sendMsg(`欢迎使用【TRSS-Yunzai v${cfg.package.version}】\n【#帮助】查看指令说明\n【#状态】查看运行状态\n【#日志】查看运行日志\n【#重启】重新启动\n【#更新】拉取 Git 更新\n【#全部更新】更新全部插件\n【#更新日志】查看更新日志\n【#设置主人】设置主人账号\n【#安装插件】查看可安装插件`)
|
| 22 |
}
|
|
|
|
| 13 |
if (!Bot.uin.includes(e.self_id))
|
| 14 |
Bot.uin.push(e.self_id)
|
| 15 |
|
| 16 |
+
if (!cfg.bot.online_msg_exp) return
|
| 17 |
const key = `Yz:loginMsg:${e.self_id}`
|
| 18 |
if (await redis.get(key)) return
|
| 19 |
+
redis.set(key, "1", { EX: cfg.bot.online_msg_exp*60 })
|
| 20 |
for (const i of cfg.master[e.self_id] || [])
|
| 21 |
e.bot.pickFriend(i).sendMsg(`欢迎使用【TRSS-Yunzai v${cfg.package.version}】\n【#帮助】查看指令说明\n【#状态】查看运行状态\n【#日志】查看运行日志\n【#重启】重新启动\n【#更新】拉取 Git 更新\n【#全部更新】更新全部插件\n【#更新日志】查看更新日志\n【#设置主人】设置主人账号\n【#安装插件】查看可安装插件`)
|
| 22 |
}
|
Yunzai/lib/events/online.js
CHANGED
|
@@ -5,14 +5,14 @@ import cfg from '../config/config.js'
|
|
| 5 |
* 监听上线事件
|
| 6 |
*/
|
| 7 |
export default class onlineEvent extends EventListener {
|
| 8 |
-
constructor
|
| 9 |
super({
|
| 10 |
event: 'online',
|
| 11 |
once: true
|
| 12 |
})
|
| 13 |
}
|
| 14 |
|
| 15 |
-
async execute
|
| 16 |
logger.mark('----^_^----')
|
| 17 |
}
|
| 18 |
}
|
|
|
|
| 5 |
* 监听上线事件
|
| 6 |
*/
|
| 7 |
export default class onlineEvent extends EventListener {
|
| 8 |
+
constructor() {
|
| 9 |
super({
|
| 10 |
event: 'online',
|
| 11 |
once: true
|
| 12 |
})
|
| 13 |
}
|
| 14 |
|
| 15 |
+
async execute() {
|
| 16 |
logger.mark('----^_^----')
|
| 17 |
}
|
| 18 |
}
|
Yunzai/lib/modules/oicq/index.js
CHANGED
|
@@ -2,20 +2,12 @@ import fs from "node:fs"
|
|
| 2 |
import path from "node:path"
|
| 3 |
|
| 4 |
function toSegment(type, data) {
|
| 5 |
-
for (const i in data)
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
data.name = path.basename(data[i])
|
| 11 |
-
data[i] = `base64://${fs.readFileSync(data[i].replace(/^file:\/\//, "")).toString("base64")}`
|
| 12 |
-
}
|
| 13 |
-
break
|
| 14 |
-
case "object":
|
| 15 |
-
if (Buffer.isBuffer(data[i]))
|
| 16 |
-
data[i] = `base64://${data[i].toString("base64")}`
|
| 17 |
}
|
| 18 |
-
}
|
| 19 |
return { type, ...data }
|
| 20 |
}
|
| 21 |
|
|
@@ -23,6 +15,15 @@ const segment = new class segment {
|
|
| 23 |
custom(type, data) {
|
| 24 |
return toSegment(type, data)
|
| 25 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
image(file, name) {
|
| 27 |
return toSegment("image", { file, name })
|
| 28 |
}
|
|
|
|
| 2 |
import path from "node:path"
|
| 3 |
|
| 4 |
function toSegment(type, data) {
|
| 5 |
+
for (const i in data)
|
| 6 |
+
if (typeof data[i] == "string" && (i == "file" || data[i].match(/^file:\/\//)) && fs.existsSync(data[i].replace(/^file:\/\//, ""))) {
|
| 7 |
+
if (i == "file" && !data.name)
|
| 8 |
+
data.name = `${Date.now()}-${path.basename(data[i])}`
|
| 9 |
+
data[i] = fs.readFileSync(data[i].replace(/^file:\/\//, ""))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
}
|
|
|
|
| 11 |
return { type, ...data }
|
| 12 |
}
|
| 13 |
|
|
|
|
| 15 |
custom(type, data) {
|
| 16 |
return toSegment(type, data)
|
| 17 |
}
|
| 18 |
+
raw(data) {
|
| 19 |
+
return toSegment("raw", { data })
|
| 20 |
+
}
|
| 21 |
+
button(...data) {
|
| 22 |
+
return toSegment("button", { data })
|
| 23 |
+
}
|
| 24 |
+
markdown(data) {
|
| 25 |
+
return toSegment("markdown", { data })
|
| 26 |
+
}
|
| 27 |
image(file, name) {
|
| 28 |
return toSegment("image", { file, name })
|
| 29 |
}
|
Yunzai/lib/plugins/loader.js
CHANGED
|
@@ -134,7 +134,7 @@ class PluginsLoader {
|
|
| 134 |
for (let val of files) {
|
| 135 |
let filepath = "../../plugins/" + val.name
|
| 136 |
let tmp = {
|
| 137 |
-
name: val.name
|
| 138 |
}
|
| 139 |
if (val.isFile()) {
|
| 140 |
if (!val.name.endsWith(".js")) continue
|
|
@@ -229,8 +229,16 @@ class PluginsLoader {
|
|
| 229 |
|
| 230 |
// 判断是否是星铁命令,若是星铁命令则标准化处理
|
| 231 |
// e.isSr = true,且命令标准化为 #星铁 开头
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
if (this.srReg.test(e.msg)) {
|
| 233 |
-
e.
|
| 234 |
e.msg = e.msg.replace(this.srReg, "#星铁")
|
| 235 |
}
|
| 236 |
|
|
@@ -260,7 +268,7 @@ class PluginsLoader {
|
|
| 260 |
e.logFnc = `[${plugin.name}][${v.fnc}]`
|
| 261 |
|
| 262 |
if (v.log !== false) {
|
| 263 |
-
logger.
|
| 264 |
}
|
| 265 |
|
| 266 |
/** 判断权限 */
|
|
@@ -521,9 +529,7 @@ class PluginsLoader {
|
|
| 521 |
try {
|
| 522 |
res = await e.replyNew(msg)
|
| 523 |
} catch (err) {
|
| 524 |
-
|
| 525 |
-
msg = lodash.truncate(JSON.stringify(msg), { length: 300 })
|
| 526 |
-
logger.error(`发送消息错误:${msg}`)
|
| 527 |
logger.error(err)
|
| 528 |
}
|
| 529 |
|
|
@@ -631,25 +637,19 @@ class PluginsLoader {
|
|
| 631 |
if (e.isGroup && e?.group?.mute_left > 0) return false
|
| 632 |
if (!e.message || e.isPrivate) return true
|
| 633 |
|
| 634 |
-
|
| 635 |
|
| 636 |
-
if (config.groupCD && this.groupCD[e.group_id])
|
| 637 |
return false
|
| 638 |
-
|
| 639 |
-
if (config.singleCD && this.singleCD[`${e.group_id}.${e.user_id}`])
|
| 640 |
return false
|
| 641 |
-
}
|
| 642 |
|
| 643 |
-
|
|
|
|
| 644 |
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
return false
|
| 648 |
-
}
|
| 649 |
-
msgThrottle[msgId] = true
|
| 650 |
-
setTimeout(() => {
|
| 651 |
-
delete msgThrottle[msgId]
|
| 652 |
-
}, 200)
|
| 653 |
|
| 654 |
return true
|
| 655 |
}
|
|
|
|
| 134 |
for (let val of files) {
|
| 135 |
let filepath = "../../plugins/" + val.name
|
| 136 |
let tmp = {
|
| 137 |
+
name: val.name
|
| 138 |
}
|
| 139 |
if (val.isFile()) {
|
| 140 |
if (!val.name.endsWith(".js")) continue
|
|
|
|
| 229 |
|
| 230 |
// 判断是否是星铁命令,若是星铁命令则标准化处理
|
| 231 |
// e.isSr = true,且命令标准化为 #星铁 开头
|
| 232 |
+
Object.defineProperty(e, "isSr", {
|
| 233 |
+
get: () => e.game === "sr",
|
| 234 |
+
set: (v) => e.game = v ? "sr" : "gs"
|
| 235 |
+
})
|
| 236 |
+
Object.defineProperty(e, "isGs", {
|
| 237 |
+
get: () => e.game === "gs",
|
| 238 |
+
set: (v) => e.game = v ? "gs" : "sr"
|
| 239 |
+
})
|
| 240 |
if (this.srReg.test(e.msg)) {
|
| 241 |
+
e.game = "sr"
|
| 242 |
e.msg = e.msg.replace(this.srReg, "#星铁")
|
| 243 |
}
|
| 244 |
|
|
|
|
| 268 |
e.logFnc = `[${plugin.name}][${v.fnc}]`
|
| 269 |
|
| 270 |
if (v.log !== false) {
|
| 271 |
+
logger.info(`${e.logFnc}${e.logText} ${lodash.truncate(e.msg, { length: 80 })}`)
|
| 272 |
}
|
| 273 |
|
| 274 |
/** 判断权限 */
|
|
|
|
| 529 |
try {
|
| 530 |
res = await e.replyNew(msg)
|
| 531 |
} catch (err) {
|
| 532 |
+
Bot.makeLog("error", `发送消息错误:${Bot.String(msg)}`, e.self_id)
|
|
|
|
|
|
|
| 533 |
logger.error(err)
|
| 534 |
}
|
| 535 |
|
|
|
|
| 637 |
if (e.isGroup && e?.group?.mute_left > 0) return false
|
| 638 |
if (!e.message || e.isPrivate) return true
|
| 639 |
|
| 640 |
+
const config = cfg.getGroup(e.self_id, e.group_id)
|
| 641 |
|
| 642 |
+
if (config.groupCD && this.groupCD[e.group_id])
|
| 643 |
return false
|
| 644 |
+
|
| 645 |
+
if (config.singleCD && this.singleCD[`${e.group_id}.${e.user_id}`])
|
| 646 |
return false
|
|
|
|
| 647 |
|
| 648 |
+
const msgId = `${e.self_id}:${e.user_id}:${e.raw_message}`
|
| 649 |
+
if (this.msgThrottle[msgId]) return false
|
| 650 |
|
| 651 |
+
this.msgThrottle[msgId] = true
|
| 652 |
+
setTimeout(() => delete this.msgThrottle[msgId], 1000)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 653 |
|
| 654 |
return true
|
| 655 |
}
|
Yunzai/lib/plugins/plugin.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
let stateArr = {}
|
| 2 |
|
| 3 |
export default class plugin {
|
|
@@ -116,4 +118,11 @@ export default class plugin {
|
|
| 116 |
delete stateArr[this.conKey(isGroup)][type]
|
| 117 |
}
|
| 118 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
}
|
|
|
|
| 1 |
+
import { Common } from '#miao'
|
| 2 |
+
|
| 3 |
let stateArr = {}
|
| 4 |
|
| 5 |
export default class plugin {
|
|
|
|
| 118 |
delete stateArr[this.conKey(isGroup)][type]
|
| 119 |
}
|
| 120 |
}
|
| 121 |
+
|
| 122 |
+
async renderImg (plugin, tpl, data, cfg) {
|
| 123 |
+
return Common.render(plugin, tpl, data, {
|
| 124 |
+
...cfg,
|
| 125 |
+
e: this.e
|
| 126 |
+
})
|
| 127 |
+
}
|
| 128 |
}
|
Yunzai/lib/plugins/runtime.js
CHANGED
|
@@ -77,7 +77,6 @@ export default class Runtime {
|
|
| 77 |
await MysInfo.initCache()
|
| 78 |
let runtime = new Runtime(e)
|
| 79 |
e.runtime = runtime
|
| 80 |
-
e.game = e.isSr ? 'sr' : 'gs'
|
| 81 |
await runtime.initUser()
|
| 82 |
return runtime
|
| 83 |
}
|
|
@@ -88,7 +87,7 @@ export default class Runtime {
|
|
| 88 |
if (user) {
|
| 89 |
e.user = new Proxy(user, {
|
| 90 |
get (self, key, receiver) {
|
| 91 |
-
let game = e.
|
| 92 |
let fnMap = {
|
| 93 |
uid: 'getUid',
|
| 94 |
uidList: 'getUidList',
|
|
@@ -238,7 +237,11 @@ export default class Runtime {
|
|
| 238 |
}
|
| 239 |
let ret = true
|
| 240 |
if (base64) {
|
| 241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
}
|
| 243 |
return cfg.retType === 'msgId' ? ret : true
|
| 244 |
}
|
|
|
|
| 77 |
await MysInfo.initCache()
|
| 78 |
let runtime = new Runtime(e)
|
| 79 |
e.runtime = runtime
|
|
|
|
| 80 |
await runtime.initUser()
|
| 81 |
return runtime
|
| 82 |
}
|
|
|
|
| 87 |
if (user) {
|
| 88 |
e.user = new Proxy(user, {
|
| 89 |
get (self, key, receiver) {
|
| 90 |
+
let game = e.game
|
| 91 |
let fnMap = {
|
| 92 |
uid: 'getUid',
|
| 93 |
uidList: 'getUidList',
|
|
|
|
| 237 |
}
|
| 238 |
let ret = true
|
| 239 |
if (base64) {
|
| 240 |
+
if (cfg.recallMsg) {
|
| 241 |
+
ret = await this.e.reply(base64, false, {})
|
| 242 |
+
} else {
|
| 243 |
+
ret = await this.e.reply(base64)
|
| 244 |
+
}
|
| 245 |
}
|
| 246 |
return cfg.retType === 'msgId' ? ret : true
|
| 247 |
}
|
Yunzai/lib/plugins/stdin.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
| 1 |
-
import fetch from "node-fetch"
|
| 2 |
import fs from "node:fs"
|
| 3 |
import path from "node:path"
|
| 4 |
import common from "../common/common.js"
|
| 5 |
-
import { fileTypeFromBuffer } from "file-type"
|
| 6 |
|
| 7 |
Bot.adapter.push(new class stdinAdapter {
|
| 8 |
constructor() {
|
|
@@ -12,59 +10,36 @@ Bot.adapter.push(new class stdinAdapter {
|
|
| 12 |
common.mkdirs(this.path)
|
| 13 |
}
|
| 14 |
|
| 15 |
-
async makeBuffer(file) {
|
| 16 |
-
if (file.match(/^base64:\/\//))
|
| 17 |
-
return Buffer.from(file.replace(/^base64:\/\//, ""), "base64")
|
| 18 |
-
else if (file.match(/^https?:\/\//))
|
| 19 |
-
return Buffer.from(await (await fetch(file)).arrayBuffer())
|
| 20 |
-
else if (fs.existsSync(file))
|
| 21 |
-
return Buffer.from(fs.readFileSync(file))
|
| 22 |
-
return file
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
async fileType(data) {
|
| 26 |
-
const file = {}
|
| 27 |
-
try {
|
| 28 |
-
file.url = data.replace(/^base64:\/\/.*/, "base64://...")
|
| 29 |
-
file.buffer = await this.makeBuffer(data)
|
| 30 |
-
file.type = await fileTypeFromBuffer(file.buffer)
|
| 31 |
-
file.path = `${this.path}${Date.now()}.${file.type.ext}`
|
| 32 |
-
} catch (err) {
|
| 33 |
-
logger.error(`文件类型检测错误:${logger.red(err)}`)
|
| 34 |
-
}
|
| 35 |
-
return file
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
async sendMsg(msg) {
|
| 39 |
if (!Array.isArray(msg))
|
| 40 |
msg = [msg]
|
| 41 |
for (let i of msg) {
|
| 42 |
if (typeof i != "object")
|
| 43 |
-
i = { type: "text",
|
| 44 |
-
else if (!i.data)
|
| 45 |
-
i = { type: i.type, data: { ...i, type: undefined }}
|
| 46 |
|
| 47 |
let file
|
| 48 |
-
if (i.
|
| 49 |
-
file = await
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
switch (i.type) {
|
| 52 |
case "text":
|
| 53 |
-
if (i.
|
| 54 |
-
i.
|
| 55 |
-
logger.info(`${logger.blue(`[${this.id}]`)} 发送文本:${i.
|
| 56 |
break
|
| 57 |
case "image":
|
| 58 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送图片:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
| 59 |
-
fs.writeFileSync(file.path, file.buffer)
|
| 60 |
break
|
| 61 |
case "record":
|
| 62 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送音频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
| 63 |
-
fs.writeFileSync(file.path, file.buffer)
|
| 64 |
break
|
| 65 |
case "video":
|
| 66 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送视频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
| 67 |
-
fs.writeFileSync(file.path, file.buffer)
|
| 68 |
break
|
| 69 |
case "reply":
|
| 70 |
break
|
|
@@ -88,7 +63,7 @@ Bot.adapter.push(new class stdinAdapter {
|
|
| 88 |
}
|
| 89 |
|
| 90 |
async sendFile(file, name = path.basename(file)) {
|
| 91 |
-
const buffer = await
|
| 92 |
if (!Buffer.isBuffer(buffer)) {
|
| 93 |
logger.error(`${logger.blue(`[${this.id}]`)} 发送文件错误:找不到文件 ${logger.red(file)}`)
|
| 94 |
return false
|
|
|
|
|
|
|
| 1 |
import fs from "node:fs"
|
| 2 |
import path from "node:path"
|
| 3 |
import common from "../common/common.js"
|
|
|
|
| 4 |
|
| 5 |
Bot.adapter.push(new class stdinAdapter {
|
| 6 |
constructor() {
|
|
|
|
| 10 |
common.mkdirs(this.path)
|
| 11 |
}
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
async sendMsg(msg) {
|
| 14 |
if (!Array.isArray(msg))
|
| 15 |
msg = [msg]
|
| 16 |
for (let i of msg) {
|
| 17 |
if (typeof i != "object")
|
| 18 |
+
i = { type: "text", text: i }
|
|
|
|
|
|
|
| 19 |
|
| 20 |
let file
|
| 21 |
+
if (i.file) {
|
| 22 |
+
file = await Bot.fileType(i.file, i.name)
|
| 23 |
+
if (Buffer.isBuffer(file.buffer)) {
|
| 24 |
+
file.path = `${this.path}${file.name || Date.now()}`
|
| 25 |
+
fs.writeFileSync(file.path, file.buffer)
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
|
| 29 |
switch (i.type) {
|
| 30 |
case "text":
|
| 31 |
+
if (i.text.match("\n"))
|
| 32 |
+
i.text = `\n${i.text}`
|
| 33 |
+
logger.info(`${logger.blue(`[${this.id}]`)} 发送文本:${i.text}`)
|
| 34 |
break
|
| 35 |
case "image":
|
| 36 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送图片:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
|
| 37 |
break
|
| 38 |
case "record":
|
| 39 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送音频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
|
| 40 |
break
|
| 41 |
case "video":
|
| 42 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送视频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
|
| 43 |
break
|
| 44 |
case "reply":
|
| 45 |
break
|
|
|
|
| 63 |
}
|
| 64 |
|
| 65 |
async sendFile(file, name = path.basename(file)) {
|
| 66 |
+
const buffer = await Bot.Buffer(file)
|
| 67 |
if (!Buffer.isBuffer(buffer)) {
|
| 68 |
logger.error(`${logger.blue(`[${this.id}]`)} 发送文件错误:找不到文件 ${logger.red(file)}`)
|
| 69 |
return false
|
Yunzai/lib/tools/log.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fs from "node:fs"
|
| 2 |
+
import childProcess from "child_process"
|
| 3 |
+
|
| 4 |
+
const _path = process.cwd()
|
| 5 |
+
|
| 6 |
+
fs.readFile(`${_path}/config/pm2/pm2.json`, `utf8`, (err, data) => {
|
| 7 |
+
if (err) {
|
| 8 |
+
console.log('pm2.json文件读取错误:', err)
|
| 9 |
+
return
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
try {
|
| 13 |
+
const config = JSON.parse(data)
|
| 14 |
+
if (config.apps && config.apps.length > 0 && config.apps[0].name) {
|
| 15 |
+
const appName = config.apps[0].name
|
| 16 |
+
runPm2Logs(appName)
|
| 17 |
+
} else {
|
| 18 |
+
console.log('读取失败:无法在pm2.json中找到name数组')
|
| 19 |
+
}
|
| 20 |
+
} catch (parseError) {
|
| 21 |
+
console.log('读取失败:json文件解析发生了错误', parseError)
|
| 22 |
+
}
|
| 23 |
+
})
|
| 24 |
+
|
| 25 |
+
function runPm2Logs(appName) {
|
| 26 |
+
const command = process.platform === 'win32' ? 'pm2.cmd' : 'pm2'
|
| 27 |
+
const args = ['logs', '--lines', '400', appName]
|
| 28 |
+
const pm2LogsProcess = childProcess.spawn(command, args, { stdio: 'inherit' })
|
| 29 |
+
pm2LogsProcess.on('exit', (code) => {
|
| 30 |
+
if (code !== 0) {
|
| 31 |
+
console.error(`pm2 logs process exited with code ${code}`)
|
| 32 |
+
}
|
| 33 |
+
})
|
| 34 |
+
}
|
Yunzai/package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Yunzai/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "trss-yunzai",
|
| 3 |
-
"version": "3.1.
|
| 4 |
"author": "TimeRainStarSky, Yoimiya-Kokomi, Le-niao",
|
| 5 |
"description": "Bot",
|
| 6 |
"main": "app.js",
|
|
@@ -13,37 +13,36 @@
|
|
| 13 |
"start": "pm2 start ./config/pm2/pm2.json",
|
| 14 |
"stop": "pm2 stop ./config/pm2/pm2.json",
|
| 15 |
"restart": "pm2 restart ./config/pm2/pm2.json",
|
| 16 |
-
"log": "node ./lib/tools/
|
| 17 |
},
|
| 18 |
"dependencies": {
|
| 19 |
"art-template": "^4.13.2",
|
| 20 |
"chalk": "^5.3.0",
|
| 21 |
"chokidar": "^3.5.3",
|
| 22 |
"express": "^4.18.2",
|
| 23 |
-
"file-type": "^18.
|
| 24 |
"https-proxy-agent": "7.0.2",
|
| 25 |
"image-size": "^1.0.2",
|
| 26 |
"lodash": "^4.17.21",
|
| 27 |
"log4js": "^6.9.1",
|
| 28 |
"md5": "^2.3.0",
|
| 29 |
-
"moment": "^2.
|
| 30 |
"node-fetch": "^3.3.2",
|
| 31 |
"node-schedule": "^2.1.1",
|
| 32 |
-
"node-xlsx": "^0.23.0",
|
| 33 |
"oicq": "link:lib/modules/oicq",
|
| 34 |
"pm2": "^5.3.0",
|
| 35 |
-
"puppeteer": "^21.
|
| 36 |
-
"redis": "^4.6.
|
| 37 |
-
"sequelize": "^6.
|
| 38 |
"sqlite3": "^5.1.6",
|
| 39 |
-
"ws": "^8.
|
| 40 |
-
"yaml": "^2.3.
|
| 41 |
},
|
| 42 |
"devDependencies": {
|
| 43 |
-
"eslint": "^8.
|
| 44 |
"eslint-config-standard": "^17.1.0",
|
| 45 |
-
"eslint-plugin-import": "^2.
|
| 46 |
-
"eslint-plugin-n": "^16.
|
| 47 |
"eslint-plugin-promise": "^6.1.1"
|
| 48 |
},
|
| 49 |
"imports": {
|
|
|
|
| 1 |
{
|
| 2 |
"name": "trss-yunzai",
|
| 3 |
+
"version": "3.1.3",
|
| 4 |
"author": "TimeRainStarSky, Yoimiya-Kokomi, Le-niao",
|
| 5 |
"description": "Bot",
|
| 6 |
"main": "app.js",
|
|
|
|
| 13 |
"start": "pm2 start ./config/pm2/pm2.json",
|
| 14 |
"stop": "pm2 stop ./config/pm2/pm2.json",
|
| 15 |
"restart": "pm2 restart ./config/pm2/pm2.json",
|
| 16 |
+
"log": "node ./lib/tools/log.js"
|
| 17 |
},
|
| 18 |
"dependencies": {
|
| 19 |
"art-template": "^4.13.2",
|
| 20 |
"chalk": "^5.3.0",
|
| 21 |
"chokidar": "^3.5.3",
|
| 22 |
"express": "^4.18.2",
|
| 23 |
+
"file-type": "^18.7.0",
|
| 24 |
"https-proxy-agent": "7.0.2",
|
| 25 |
"image-size": "^1.0.2",
|
| 26 |
"lodash": "^4.17.21",
|
| 27 |
"log4js": "^6.9.1",
|
| 28 |
"md5": "^2.3.0",
|
| 29 |
+
"moment": "^2.30.1",
|
| 30 |
"node-fetch": "^3.3.2",
|
| 31 |
"node-schedule": "^2.1.1",
|
|
|
|
| 32 |
"oicq": "link:lib/modules/oicq",
|
| 33 |
"pm2": "^5.3.0",
|
| 34 |
+
"puppeteer": "^21.6.1",
|
| 35 |
+
"redis": "^4.6.12",
|
| 36 |
+
"sequelize": "^6.35.2",
|
| 37 |
"sqlite3": "^5.1.6",
|
| 38 |
+
"ws": "^8.16.0",
|
| 39 |
+
"yaml": "^2.3.4"
|
| 40 |
},
|
| 41 |
"devDependencies": {
|
| 42 |
+
"eslint": "^8.56.0",
|
| 43 |
"eslint-config-standard": "^17.1.0",
|
| 44 |
+
"eslint-plugin-import": "^2.29.1",
|
| 45 |
+
"eslint-plugin-n": "^16.5.0",
|
| 46 |
"eslint-plugin-promise": "^6.1.1"
|
| 47 |
},
|
| 48 |
"imports": {
|
Yunzai/pnpm-lock.yaml
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|