feat: 格式化&修正类型
This commit is contained in:
parent
94b0df3b23
commit
5e0c0dc756
|
@ -0,0 +1 @@
|
|||
node_modules
|
|
@ -0,0 +1,21 @@
|
|||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
|
||||
# 旧版文件夹
|
||||
config
|
||||
docker
|
||||
lib
|
||||
plugins
|
||||
renderers
|
||||
|
||||
# 旧版文件
|
||||
|
||||
CHANGELOG.md
|
||||
docker-compose.yaml
|
||||
miao.js
|
||||
|
||||
|
||||
# 缓存目录
|
||||
data
|
||||
trss.js
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 80,
|
||||
"trailingComma": "none",
|
||||
"useTabs": false,
|
||||
"proseWrap": "preserve",
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "auto",
|
||||
"quoteProps": "consistent",
|
||||
"vueIndentScriptAndStyle": true
|
||||
}
|
18
README.md
18
README.md
|
@ -12,19 +12,17 @@ git clone --depth=1 -b system https://github.com/yoimiya-kokomi/Miao-Yunzai.git
|
|||
|
||||
## 功能列表
|
||||
|
||||
|
||||
| 功能 | 指令 | 说明 |
|
||||
|-------| ----- |------ |
|
||||
| 功能 | 指令 | 说明 |
|
||||
| ---- | ------------------- | ---- |
|
||||
| 日志 | #更新日志 #运行日志 | 嘎嘎 |
|
||||
| 更新| #更新 #全部更新 | 嘎嘎 |
|
||||
| 状态 | #状态 | 嘎嘎 |
|
||||
| 运行 | #重启 #关机 | 嘎嘎 |
|
||||
| 娱乐 | #复读 | 嘎嘎|
|
||||
| 表情 | #添加xxx | 嘎嘎|
|
||||
|
||||
| 更新 | #更新 #全部更新 | 嘎嘎 |
|
||||
| 状态 | #状态 | 嘎嘎 |
|
||||
| 运行 | #重启 #关机 | 嘎嘎 |
|
||||
| 娱乐 | #复读 | 嘎嘎 |
|
||||
| 表情 | #添加xxx | 嘎嘎 |
|
||||
|
||||
## 图片开发
|
||||
|
||||
```sh
|
||||
npm run image
|
||||
```
|
||||
```
|
||||
|
|
293
apps/add.ts
293
apps/add.ts
|
@ -1,10 +1,17 @@
|
|||
|
||||
import fs from 'node:fs'
|
||||
import {
|
||||
createWriteStream,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
readdirSync,
|
||||
unlink,
|
||||
writeFileSync
|
||||
} from 'node:fs'
|
||||
import lodash from 'lodash'
|
||||
import { pipeline } from 'stream'
|
||||
import { promisify } from 'util'
|
||||
import fetch from 'node-fetch'
|
||||
import moment from 'moment'
|
||||
import { pipeline } from 'stream'
|
||||
import { promisify } from 'util'
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
import { makeForwardMsg } from 'yunzai/core'
|
||||
|
@ -18,15 +25,16 @@ export class add extends Plugin {
|
|||
path = './data/textJson/'
|
||||
facePath = './data/face/'
|
||||
isGlobal = false
|
||||
keyWord = null
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
name: '添加表情',
|
||||
dsc: '添加表情,文字等',
|
||||
*/
|
||||
super();
|
||||
super()
|
||||
this.priority = 50000
|
||||
this.rule = [
|
||||
{
|
||||
|
@ -49,46 +57,49 @@ export class add extends Plugin {
|
|||
{
|
||||
reg: /#(全局)?(表情|词条)(.*)/,
|
||||
fnc: this.list.name
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async accept() {
|
||||
/** 处理消息 */
|
||||
if (this.e.atBot && this.e.msg && this.e?.msg.includes('添加') && !this.e?.msg.includes('#')) {
|
||||
if (
|
||||
this.e.atBot &&
|
||||
this.e.msg &&
|
||||
this.e?.msg.includes('添加') &&
|
||||
!this.e?.msg.includes('#')
|
||||
) {
|
||||
this.e.msg = '#' + this.e.msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async init() {
|
||||
if (!fs.existsSync(this.path)) {
|
||||
fs.mkdirSync(this.path)
|
||||
if (!existsSync(this.path)) {
|
||||
mkdirSync(this.path)
|
||||
}
|
||||
if (!fs.existsSync(this.facePath)) {
|
||||
fs.mkdirSync(this.facePath)
|
||||
if (!existsSync(this.facePath)) {
|
||||
mkdirSync(this.facePath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
get grpKey() {
|
||||
return `Yz:group_id:${this.e.user_id}`
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async add() {
|
||||
this.isGlobal = this.e?.msg.includes("全局");
|
||||
this.isGlobal = this.e?.msg.includes('全局')
|
||||
await this.getGroupId()
|
||||
|
||||
if (!this.group_id) {
|
||||
|
@ -119,13 +130,13 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async getGroupId() {
|
||||
/** 添加全局表情,存入到机器人qq文件中 */
|
||||
if (this.isGlobal) {
|
||||
this.group_id = this.e.bot.uin;
|
||||
return this.e.bot.uin;
|
||||
this.group_id = this.e.bot.uin
|
||||
return this.e.bot.uin
|
||||
}
|
||||
|
||||
if (this.e.isGroup) {
|
||||
|
@ -137,7 +148,7 @@ export class add extends Plugin {
|
|||
// redis获取
|
||||
let groupId = await redis.get(this.grpKey)
|
||||
if (groupId) {
|
||||
this.group_id = groupId
|
||||
this.group_id = Number(groupId)
|
||||
return this.group_id
|
||||
}
|
||||
|
||||
|
@ -145,7 +156,7 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
checkAuth() {
|
||||
if (this.e.isMaster) return true
|
||||
|
@ -177,7 +188,7 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
checkKeyWord() {
|
||||
if (this.e.img && this.e.img.length > 1) {
|
||||
|
@ -186,7 +197,9 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
if (this.e.at) {
|
||||
let at = lodash.filter(this.e.message, (o) => { return o.type == 'at' && o.qq != this.e.bot.uin })
|
||||
let at = lodash.filter(this.e.message, o => {
|
||||
return o.type == 'at' && o.qq != this.e.bot.uin
|
||||
})
|
||||
if (at.length > 1) {
|
||||
this.e.reply('添加错误:只能@一个人当关键词')
|
||||
return false
|
||||
|
@ -203,7 +216,7 @@ export class add extends Plugin {
|
|||
|
||||
/**
|
||||
* 单独添加
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
async singleAdd() {
|
||||
if (this.e.message.length != 2) return false
|
||||
|
@ -211,7 +224,7 @@ export class add extends Plugin {
|
|||
if (!this.e.msg || !msg.image) return false
|
||||
|
||||
// #全局添加文字+表情包,无法正确添加到全局路径
|
||||
this.e.isGlobal = this.isGlobal;
|
||||
this.e.isGlobal = this.isGlobal
|
||||
let keyWord = this.e.msg.replace(/#|#|图片|表情|添加|全局/g, '').trim()
|
||||
if (!keyWord) return false
|
||||
|
||||
|
@ -231,9 +244,10 @@ export class add extends Plugin {
|
|||
* 获取添加关键词
|
||||
*/
|
||||
getKeyWord() {
|
||||
this.e.isGlobal = this.e.msg.includes("全局");
|
||||
this.e.isGlobal = this.e.msg.includes('全局')
|
||||
|
||||
this.keyWord = this.e.toString()
|
||||
this.keyWord = this.e
|
||||
.toString()
|
||||
.trim()
|
||||
/** 过滤#添加 */
|
||||
.replace(/#|#|图片|表情|添加|删除|全局/g, '')
|
||||
|
@ -251,8 +265,8 @@ export class add extends Plugin {
|
|||
|
||||
/**
|
||||
* 过滤别名
|
||||
* @param msg
|
||||
* @returns
|
||||
* @param msg
|
||||
* @returns
|
||||
*/
|
||||
trimAlias(msg) {
|
||||
let groupCfg = cfg.getGroup(this.group_id)
|
||||
|
@ -271,10 +285,10 @@ export class add extends Plugin {
|
|||
|
||||
/**
|
||||
* 添加内容
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
async addContext() {
|
||||
this.isGlobal = this.e.isGlobal || this.getContext()?.addContext?.isGlobal;
|
||||
this.isGlobal = this.e.isGlobal || this.getContext()?.addContext?.isGlobal
|
||||
await this.getGroupId()
|
||||
/** 关键词 */
|
||||
let keyWord = this.keyWord || this.getContext()?.addContext?.keyWord
|
||||
|
@ -287,23 +301,23 @@ export class add extends Plugin {
|
|||
this.finish('addContext')
|
||||
|
||||
for (let i in message) {
|
||||
if (message[i].type == "at") {
|
||||
if (message[i].type == 'at') {
|
||||
if (message[i].qq == this.e.bot.uin) {
|
||||
this.e.reply("添加内容不能@机器人!");
|
||||
return;
|
||||
this.e.reply('添加内容不能@机器人!')
|
||||
return
|
||||
}
|
||||
}
|
||||
if (message[i].type == "file") {
|
||||
this.e.reply("添加错误:禁止添加文件");
|
||||
return;
|
||||
if (message[i].type == 'file') {
|
||||
this.e.reply('添加错误:禁止添加文件')
|
||||
return
|
||||
}
|
||||
|
||||
// 保存用户信息用于追溯添加者
|
||||
message[i].from_user = {
|
||||
card: this.e.sender.card,
|
||||
nickname: this.e.sender.nickname,
|
||||
user_id: this.e.sender.user_id,
|
||||
};
|
||||
user_id: this.e.sender.user_id
|
||||
}
|
||||
}
|
||||
|
||||
if (message.length == 1 && message[0].type == 'image') {
|
||||
|
@ -338,10 +352,10 @@ export class add extends Plugin {
|
|||
|
||||
/**
|
||||
* 添加成功回复消息
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
getRetMsg() {
|
||||
let retMsg = this.getContext()
|
||||
const retMsg = this.getContext()
|
||||
let msg = ''
|
||||
if (retMsg?.addContext?.message) {
|
||||
msg = retMsg.addContext.message
|
||||
|
@ -349,7 +363,9 @@ export class add extends Plugin {
|
|||
for (let i in msg) {
|
||||
if (msg[i].type == 'text' && msg[i].text.includes('添加')) {
|
||||
msg[i].text = this.trimAlias(msg[i].text)
|
||||
msg[i].text = msg[i].text.trim().replace(/#|#|图片|表情|添加|全局/g, '')
|
||||
msg[i].text = msg[i].text
|
||||
.trim()
|
||||
.replace(/#|#|图片|表情|添加|全局/g, '')
|
||||
if (!msg[i].text) delete msg[i]
|
||||
continue
|
||||
}
|
||||
|
@ -370,7 +386,7 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
saveJson() {
|
||||
let obj = {}
|
||||
|
@ -378,36 +394,39 @@ export class add extends Plugin {
|
|||
obj[k] = v
|
||||
}
|
||||
|
||||
fs.writeFileSync(`${this.path}${this.group_id}.json`, JSON.stringify(obj, '', '\t'))
|
||||
writeFileSync(
|
||||
`${this.path}${this.group_id}.json`,
|
||||
JSON.stringify(obj, '', '\t')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
saveGlobalJson() {
|
||||
let obj = {};
|
||||
let obj = {}
|
||||
for (let [k, v] of textArr[this.e.bot.uin]) {
|
||||
obj[k] = v;
|
||||
obj[k] = v
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
writeFileSync(
|
||||
`${this.path}${this.e.bot.uin}.json`,
|
||||
JSON.stringify(obj, "", "\t")
|
||||
);
|
||||
JSON.stringify(obj, '', '\t')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param url
|
||||
* @param keyWord
|
||||
* @returns
|
||||
*
|
||||
* @param url
|
||||
* @param keyWord
|
||||
* @returns
|
||||
*/
|
||||
async saveImg(url, keyWord) {
|
||||
let groupCfg = cfg.getGroup(this.group_id)
|
||||
let savePath = `${this.facePath}${this.group_id}/`
|
||||
|
||||
if (!fs.existsSync(savePath)) {
|
||||
fs.mkdirSync(savePath)
|
||||
if (!existsSync(savePath)) {
|
||||
mkdirSync(savePath)
|
||||
}
|
||||
|
||||
const response = await fetch(url)
|
||||
|
@ -428,21 +447,21 @@ export class add extends Plugin {
|
|||
let type = response.headers.get('content-type').split('/')[1]
|
||||
if (type == 'jpeg') type = 'jpg'
|
||||
|
||||
if (fs.existsSync(`${savePath}${keyWord}.${type}`)) {
|
||||
if (existsSync(`${savePath}${keyWord}.${type}`)) {
|
||||
keyWord = `${keyWord}_${moment().format('X')}`
|
||||
}
|
||||
|
||||
savePath = `${savePath}${keyWord}.${type}`
|
||||
|
||||
const streamPipeline = promisify(pipeline)
|
||||
await streamPipeline(response.body, fs.createWriteStream(savePath))
|
||||
await streamPipeline(response.body, createWriteStream(savePath))
|
||||
|
||||
return savePath
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async getText() {
|
||||
if (!this.e.message) return false
|
||||
|
@ -457,7 +476,8 @@ export class add extends Plugin {
|
|||
|
||||
this.initGlobalTextArr()
|
||||
|
||||
let keyWord = this.e.toString()
|
||||
let keyWord = this.e
|
||||
.toString()
|
||||
.replace(/#|#/g, '')
|
||||
.replace(`{at:${this.e.bot.uin}}`, '')
|
||||
.trim()
|
||||
|
@ -468,7 +488,11 @@ export class add extends Plugin {
|
|||
if (isNaN(keyWord)) {
|
||||
num = keyWord.trim().match(/[0-9]+$/)?.[0]
|
||||
|
||||
if (!isNaN(num) && !textArr[this.group_id].has(keyWord) && !textArr[this.e.bot.uin].has(keyWord)) {
|
||||
if (
|
||||
!isNaN(num) &&
|
||||
!textArr[this.group_id].has(keyWord) &&
|
||||
!textArr[this.e.bot.uin].has(keyWord)
|
||||
) {
|
||||
keyWord = lodash.trimEnd(keyWord, num).trim()
|
||||
num--
|
||||
}
|
||||
|
@ -489,7 +513,7 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
if (msg[0] && msg[0].local) {
|
||||
if (fs.existsSync(msg[0].local)) {
|
||||
if (existsSync(msg[0].local)) {
|
||||
let tmp = segment.image(msg[0].local)
|
||||
tmp.asface = msg[0].asface
|
||||
msg = tmp
|
||||
|
@ -502,7 +526,9 @@ export class add extends Plugin {
|
|||
if (Array.isArray(msg)) {
|
||||
msg.forEach(m => {
|
||||
/** 去除回复@@ */
|
||||
if (m?.type == 'at') { delete m.text }
|
||||
if (m?.type == 'at') {
|
||||
delete m.text
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -516,9 +542,9 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param keyWord
|
||||
* @param num
|
||||
*
|
||||
* @param keyWord
|
||||
* @param num
|
||||
*/
|
||||
expiredMsg(keyWord, num) {
|
||||
logger.mark(`[发送表情]${this.e.logText} ${keyWord} 表情已过期失效`)
|
||||
|
@ -537,7 +563,7 @@ export class add extends Plugin {
|
|||
|
||||
/**
|
||||
* 初始化已添加内容
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
initTextArr() {
|
||||
if (textArr[this.group_id]) return
|
||||
|
@ -545,12 +571,12 @@ export class add extends Plugin {
|
|||
textArr[this.group_id] = new Map()
|
||||
|
||||
let path = `${this.path}${this.group_id}.json`
|
||||
if (!fs.existsSync(path)) {
|
||||
if (!existsSync(path)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let text = JSON.parse(fs.readFileSync(path, 'utf8'))
|
||||
let text = JSON.parse(readFileSync(path, 'utf8'))
|
||||
for (let i in text) {
|
||||
if (text[i][0] && !Array.isArray(text[i][0])) {
|
||||
text[i] = [text[i]]
|
||||
|
@ -567,8 +593,10 @@ export class add extends Plugin {
|
|||
/** 加载表情 */
|
||||
let facePath = `${this.facePath}${this.group_id}`
|
||||
|
||||
if (fs.existsSync(facePath)) {
|
||||
const files = fs.readdirSync(`${this.facePath}${this.group_id}`).filter(file => /\.(jpeg|jpg|png|gif)$/g.test(file))
|
||||
if (existsSync(facePath)) {
|
||||
const files = readdirSync(`${this.facePath}${this.group_id}`).filter(
|
||||
file => /\.(jpeg|jpg|png|gif)$/g.test(file)
|
||||
)
|
||||
for (let val of files) {
|
||||
let tmp = val.split('.')
|
||||
tmp[0] = tmp[0].replace(/_[0-9]{10}$/, '')
|
||||
|
@ -576,91 +604,97 @@ export class add extends Plugin {
|
|||
|
||||
if (textArr[this.group_id].has(tmp[0])) continue
|
||||
|
||||
textArr[this.group_id].set(tmp[0], [[{
|
||||
local: `${facePath}/${val}`,
|
||||
asface: true
|
||||
}]])
|
||||
textArr[this.group_id].set(tmp[0], [
|
||||
[
|
||||
{
|
||||
local: `${facePath}/${val}`,
|
||||
asface: true
|
||||
}
|
||||
]
|
||||
])
|
||||
}
|
||||
|
||||
this.saveJson()
|
||||
} else {
|
||||
fs.mkdirSync(facePath)
|
||||
mkdirSync(facePath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化全局已添加内容
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
initGlobalTextArr() {
|
||||
if (textArr[this.e.bot.uin]) return;
|
||||
if (textArr[this.e.bot.uin]) return
|
||||
|
||||
textArr[this.e.bot.uin] = new Map();
|
||||
textArr[this.e.bot.uin] = new Map()
|
||||
|
||||
let globalPath = `${this.path}${this.e.bot.uin}.json`;
|
||||
if (!fs.existsSync(globalPath)) {
|
||||
return;
|
||||
let globalPath = `${this.path}${this.e.bot.uin}.json`
|
||||
if (!existsSync(globalPath)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let text = JSON.parse(fs.readFileSync(globalPath, "utf8"));
|
||||
let text = JSON.parse(readFileSync(globalPath, 'utf8'))
|
||||
|
||||
for (let i in text) {
|
||||
if (text[i][0] && !Array.isArray(text[i][0])) {
|
||||
text[i] = [text[i]];
|
||||
text[i] = [text[i]]
|
||||
}
|
||||
textArr[this.e.bot.uin].set(String(i), text[i]);
|
||||
textArr[this.e.bot.uin].set(String(i), text[i])
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`json格式错误:${globalPath}`);
|
||||
delete textArr[this.e.bot.uin];
|
||||
return false;
|
||||
logger.error(`json格式错误:${globalPath}`)
|
||||
delete textArr[this.e.bot.uin]
|
||||
return false
|
||||
}
|
||||
|
||||
/** 加载表情 */
|
||||
let globalFacePath = `${this.facePath}${this.e.bot.uin}`;
|
||||
let globalFacePath = `${this.facePath}${this.e.bot.uin}`
|
||||
|
||||
if (fs.existsSync(globalFacePath)) {
|
||||
if (existsSync(globalFacePath)) {
|
||||
const files = fs
|
||||
.readdirSync(`${this.facePath}${this.e.bot.uin}`)
|
||||
.filter((file) => /\.(jpeg|jpg|png|gif)$/g.test(file));
|
||||
.filter(file => /\.(jpeg|jpg|png|gif)$/g.test(file))
|
||||
|
||||
for (let val of files) {
|
||||
let tmp = val.split(".");
|
||||
tmp[0] = tmp[0].replace(/_[0-9]{10}$/, "");
|
||||
if (/at|image/g.test(val)) continue;
|
||||
let tmp = val.split('.')
|
||||
tmp[0] = tmp[0].replace(/_[0-9]{10}$/, '')
|
||||
if (/at|image/g.test(val)) continue
|
||||
|
||||
if (textArr[this.e.bot.uin].has(tmp[0])) continue;
|
||||
if (textArr[this.e.bot.uin].has(tmp[0])) continue
|
||||
|
||||
textArr[this.e.bot.uin].set(tmp[0], [
|
||||
[
|
||||
{
|
||||
local: `${globalFacePath}/${val}`,
|
||||
asface: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
asface: true
|
||||
}
|
||||
]
|
||||
])
|
||||
}
|
||||
|
||||
this.saveGlobalJson();
|
||||
this.saveGlobalJson()
|
||||
} else {
|
||||
fs.mkdirSync(globalFacePath);
|
||||
mkdirSync(globalFacePath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async del() {
|
||||
this.isGlobal = this.e?.msg.includes("全局");
|
||||
this.isGlobal = this.e?.msg.includes('全局')
|
||||
await this.getGroupId()
|
||||
if (!this.group_id) return false
|
||||
if (!this.checkAuth()) return
|
||||
|
||||
this.initTextArr()
|
||||
|
||||
let keyWord = this.e.toString().replace(/#|#|图片|表情|删除|全部|全局/g, '')
|
||||
let keyWord = this.e
|
||||
.toString()
|
||||
.replace(/#|#|图片|表情|删除|全部|全局/g, '')
|
||||
|
||||
keyWord = this.trimAlias(keyWord)
|
||||
|
||||
|
@ -736,7 +770,7 @@ export class add extends Plugin {
|
|||
img = item[0]
|
||||
}
|
||||
if (img.local) {
|
||||
fs.unlink(img.local, () => { })
|
||||
unlink(img.local, () => {})
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -744,10 +778,10 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async list() {
|
||||
this.isGlobal = this.e?.msg.includes("全局");
|
||||
this.isGlobal = this.e?.msg.includes('全局')
|
||||
|
||||
let page = 1
|
||||
let pageSize = 100
|
||||
|
@ -794,7 +828,9 @@ export class add extends Plugin {
|
|||
return
|
||||
}
|
||||
|
||||
let msg = [], result = [], num = 0
|
||||
let msg = [],
|
||||
result = [],
|
||||
num = 0
|
||||
for (let i in arr) {
|
||||
if (num >= page * pageSize) break
|
||||
|
||||
|
@ -816,11 +852,11 @@ export class add extends Plugin {
|
|||
result.push([msg[i]])
|
||||
}
|
||||
/** 计算页数 */
|
||||
let book = count / pageSize;
|
||||
let book = count / pageSize
|
||||
if (book % 1 === 0) {
|
||||
book = result;
|
||||
book = result
|
||||
} else {
|
||||
book = Math.floor(book) + 1;
|
||||
book = Math.floor(book) + 1
|
||||
}
|
||||
if (type == 'list' && msg.length >= pageSize) {
|
||||
result.push(`更多内容请翻页查看\n如:#表情列表${Number(page) + 1}`)
|
||||
|
@ -837,17 +873,19 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
pagination(pageNo, pageSize, array) {
|
||||
let offset = (pageNo - 1) * pageSize
|
||||
return offset + pageSize >= array.length ? array.slice(offset, array.length) : array.slice(offset, offset + pageSize)
|
||||
return offset + pageSize >= array.length
|
||||
? array.slice(offset, array.length)
|
||||
: array.slice(offset, offset + pageSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键词转换成可发送消息
|
||||
* @param msg
|
||||
* @returns
|
||||
* @param msg
|
||||
* @returns
|
||||
*/
|
||||
async keyWordTran(msg) {
|
||||
/** 图片 */
|
||||
|
@ -864,7 +902,9 @@ export class add extends Plugin {
|
|||
|
||||
for (let qq of tmp) {
|
||||
qq = qq.match(/[1-9][0-9]{4,14}/g)[0]
|
||||
let member = await await this.e.bot.getGroupMemberInfo(this.group_id, Number(qq)).catch(() => { })
|
||||
let member = await await this.e.bot
|
||||
.getGroupMemberInfo(this.group_id, Number(qq))
|
||||
.catch(() => {})
|
||||
let name = member?.card ?? member?.nickname
|
||||
if (!name) continue
|
||||
msg = msg.replace(`{at:${qq}}`, `@${name}`)
|
||||
|
@ -883,8 +923,8 @@ export class add extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async faceDetail() {
|
||||
if (!this.e.message) return false
|
||||
|
@ -913,7 +953,6 @@ export class add extends Plugin {
|
|||
return
|
||||
}
|
||||
|
||||
|
||||
// process faces into replyArr in type:
|
||||
let replyArr = []
|
||||
for (let i = 0; i < faces.length; i++) {
|
||||
|
@ -944,7 +983,11 @@ export class add extends Plugin {
|
|||
return
|
||||
}
|
||||
|
||||
let forwardMsg = await makeForwardMsg(this.e, replyArr, `表情${keyWord}详情`)
|
||||
let forwardMsg = await makeForwardMsg(
|
||||
this.e,
|
||||
replyArr,
|
||||
`表情${keyWord}详情`
|
||||
)
|
||||
|
||||
this.e.reply(forwardMsg)
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
export class disFriPoke extends Plugin {
|
||||
constructor() {
|
||||
/**
|
||||
constructor() {
|
||||
/**
|
||||
name: '禁止私聊',
|
||||
dsc: '对私聊禁用做处理当开启私聊禁用时只接收cookie以及抽卡链接',
|
||||
*/
|
||||
super()
|
||||
this.event = 'notice.friend.poke'
|
||||
this.priority = 0
|
||||
}
|
||||
/**
|
||||
* default
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (!cfg.other?.disablePrivate) return
|
||||
if (this.e.isMaster) return
|
||||
this.e.reply(cfg.other.disableMsg)
|
||||
return 'return'
|
||||
}
|
||||
}
|
||||
super()
|
||||
this.event = 'notice.friend.poke'
|
||||
this.priority = 0
|
||||
}
|
||||
/**
|
||||
* default
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (!cfg.other?.disablePrivate) return
|
||||
if (this.e.isMaster) return
|
||||
this.e.reply(cfg.other.disableMsg)
|
||||
return 'return'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class disPri extends Plugin {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -19,8 +18,8 @@ export class disPri extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (!cfg.other?.disablePrivate) return
|
||||
|
@ -29,7 +28,7 @@ export class disPri extends Plugin {
|
|||
|
||||
/** 发送日志文件,xlsx,json */
|
||||
if (this.e.file) {
|
||||
if (!/(.*)\.txt|xlsx|json/ig.test(this.e.file?.name)) {
|
||||
if (!/(.*)\.txt|xlsx|json/gi.test(this.e.file?.name)) {
|
||||
this.sendTips()
|
||||
return 'return'
|
||||
} else {
|
||||
|
@ -38,16 +37,21 @@ export class disPri extends Plugin {
|
|||
}
|
||||
|
||||
/** 绑定ck,抽卡链接 */
|
||||
let wordReg = /(.*)(ltoken|_MHYUUID|authkey=)(.*)|导出记录(json)*|(记录|安卓|苹果|ck|cookie|体力)帮助|^帮助$|^#*(删除|我的)ck$|^#(我的)?(uid|UID)[0-9]{0,2}$/g
|
||||
let wordReg =
|
||||
/(.*)(ltoken|_MHYUUID|authkey=)(.*)|导出记录(json)*|(记录|安卓|苹果|ck|cookie|体力)帮助|^帮助$|^#*(删除|我的)ck$|^#(我的)?(uid|UID)[0-9]{0,2}$/g
|
||||
/** 自定义通行字符 */
|
||||
let disableAdopt = cfg.other?.disableAdopt
|
||||
if (!Array.isArray(disableAdopt)) {
|
||||
disableAdopt = []
|
||||
}
|
||||
disableAdopt = disableAdopt.filter(str => str != null && str !== '');
|
||||
disableAdopt = disableAdopt.filter(str => str != null && str !== '')
|
||||
let disableReg = `(.*)(${disableAdopt.join('|')})(.*)`
|
||||
if (this.e.raw_message) {
|
||||
if (!new RegExp(wordReg).test(this.e.raw_message) && (disableAdopt.length === 0 || !new RegExp(disableReg).test(this.e.raw_message))) {
|
||||
if (
|
||||
!new RegExp(wordReg).test(this.e.raw_message) &&
|
||||
(disableAdopt.length === 0 ||
|
||||
!new RegExp(disableReg).test(this.e.raw_message))
|
||||
) {
|
||||
this.sendTips()
|
||||
return 'return'
|
||||
}
|
||||
|
@ -55,8 +59,8 @@ export class disPri extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async sendTips() {
|
||||
/** 冷却cd 10s */
|
||||
|
@ -72,4 +76,4 @@ export class disPri extends Plugin {
|
|||
|
||||
redis.setEx(key, cd, '1')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { sleep } from 'yunzai/utils'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class friend extends Plugin {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -16,18 +15,18 @@ export class friend extends Plugin {
|
|||
dsc: '自动同意好友',
|
||||
*/
|
||||
super()
|
||||
this.event = 'request.friend'
|
||||
this.event = 'request.friend'
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async accept() {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (this.e.sub_type == 'add' || this.e.sub_type == 'single') {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (cfg.other.autoFriend == 1) {
|
||||
logger.mark(`[自动同意][添加好友] ${this.e.user_id}`)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class invite extends Plugin {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -15,17 +14,17 @@ export class invite extends Plugin {
|
|||
dsc: '主人邀请自动进群',
|
||||
*/
|
||||
super()
|
||||
this.event = 'request.group.invite'
|
||||
this.event = 'request.group.invite'
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if(/group/.test(this.event)){
|
||||
if (/group/.test(this.event)) {
|
||||
this.e.isGroup = true
|
||||
}
|
||||
if(!this.e.isGroup) return
|
||||
if (!this.e.isGroup) return
|
||||
//
|
||||
if (!cfg.masterQQ || !cfg.masterQQ.includes(String(this.e.user_id))) {
|
||||
logger.mark(`[邀请加群]:${this.e.group_name}:${this.e.group_id}`)
|
||||
|
@ -33,8 +32,10 @@ export class invite extends Plugin {
|
|||
}
|
||||
logger.mark(`[主人邀请加群]:${this.e.group_name}:${this.e.group_id}`)
|
||||
this.e.approve(true)
|
||||
this.e.bot.sendPrivateMsg(this.e.user_id, `已同意加群:${this.e.group_name}`).catch((err) => {
|
||||
logger.error(err)
|
||||
})
|
||||
this.e.bot
|
||||
.sendPrivateMsg(this.e.user_id, `已同意加群:${this.e.group_name}`)
|
||||
.catch(err => {
|
||||
logger.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Plugin, segment } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class newcomer extends Plugin {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -12,13 +12,13 @@ export class newcomer extends Plugin {
|
|||
dsc: '新人入群欢迎',
|
||||
*/
|
||||
super()
|
||||
this.event = 'notice.group.increase'
|
||||
this.event = 'notice.group.increase'
|
||||
this.priority = 5000
|
||||
}
|
||||
|
||||
/**
|
||||
* 接受到消息都会执行一次
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
/** 定义入群欢迎内容 */
|
||||
|
@ -38,4 +38,3 @@ export class newcomer extends Plugin {
|
|||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
import { Plugin } from 'yunzai/core'
|
||||
export class outNotice extends Plugin {
|
||||
tips = '退群了'
|
||||
constructor() {
|
||||
/**
|
||||
tips = '退群了'
|
||||
constructor() {
|
||||
/**
|
||||
name: '退群通知',
|
||||
dsc: 'xx退群了',
|
||||
*/
|
||||
super()
|
||||
this.event = 'notice.group.decrease'
|
||||
super()
|
||||
this.event = 'notice.group.decrease'
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (this.e.user_id == this.e.bot.uin) return
|
||||
let name = null,
|
||||
msg = null
|
||||
if (this.e.member) {
|
||||
name = this.e.member.card || this.e.member.nickname
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (this.e.user_id == this.e.bot.uin) return
|
||||
let name = null, msg = null
|
||||
if (this.e.member) {
|
||||
name = this.e.member.card || this.e.member.nickname
|
||||
}
|
||||
if (name) {
|
||||
msg = `${name}(${this.e.user_id}) ${this.tips}`
|
||||
} else {
|
||||
msg = `${this.e.user_id} ${this.tips}`
|
||||
}
|
||||
logger.mark(`[退出通知]${this.e.logText} ${msg}`)
|
||||
await this.reply(msg)
|
||||
if (name) {
|
||||
msg = `${name}(${this.e.user_id}) ${this.tips}`
|
||||
} else {
|
||||
msg = `${this.e.user_id} ${this.tips}`
|
||||
}
|
||||
logger.mark(`[退出通知]${this.e.logText} ${msg}`)
|
||||
await this.reply(msg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class quit extends Plugin {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -16,17 +16,17 @@ export class quit extends Plugin {
|
|||
this.event = 'notice.group.increase'
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async accept() {
|
||||
if (this.e.user_id != this.e.bot.uin) return
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
let other = cfg.other
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (other.autoQuit <= 0) return
|
||||
/**
|
||||
|
@ -44,19 +44,19 @@ export class quit extends Plugin {
|
|||
*/
|
||||
if (Array.from(gl).length <= other.autoQuit && !this.e.group.is_owner) {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
await this.e.reply('禁止拉群,已自动退出')
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
logger.mark(`[自动退群] ${this.e.group_id}`)
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
setTimeout(() => {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
this.e.group.quit()
|
||||
}, 2000)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Plugin } from 'yunzai/core'
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class example2 extends Plugin {
|
||||
constructor () {
|
||||
constructor() {
|
||||
/**
|
||||
name: '复读',
|
||||
dsc: '复读用户发送的内容,然后撤回',
|
||||
|
@ -18,9 +18,9 @@ export class example2 extends Plugin {
|
|||
]
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
async repeat () {
|
||||
async repeat() {
|
||||
/** 设置上下文,后续接收到内容会执行doRep方法 */
|
||||
this.setContext('doRep')
|
||||
/** 回复 */
|
||||
|
@ -29,7 +29,7 @@ export class example2 extends Plugin {
|
|||
/**
|
||||
* 接受内容
|
||||
*/
|
||||
doRep () {
|
||||
doRep() {
|
||||
/** 复读内容 */
|
||||
this.reply(this.e.message, false, { recallMsg: 5 })
|
||||
/** 结束上下文 */
|
||||
|
|
|
@ -15,4 +15,28 @@ export * from './status.js'
|
|||
export * from './update.js'
|
||||
export * from './example2.js'
|
||||
export * from './event/newcomer.js'
|
||||
export * from './event/outNotice.js'
|
||||
export * from './event/outNotice.js'
|
||||
|
||||
import { Messages, Segment } from 'yunzai/core'
|
||||
import { imgae } from '../image.tsx'
|
||||
import { movies } from '../data.ts'
|
||||
const message = new Messages()
|
||||
message.response(/^你好/, async e => {
|
||||
const UID = e.user_id
|
||||
// render 是异步的,因此此处也是异步的
|
||||
const img = await imgae.createHello(UID, {
|
||||
data: { name: 'word' },
|
||||
movies
|
||||
})
|
||||
// 判断是否成功
|
||||
if (typeof img !== 'boolean') {
|
||||
// 图片
|
||||
e.reply(Segment.image(img))
|
||||
} else {
|
||||
e.reply('你好')
|
||||
}
|
||||
})
|
||||
|
||||
const word = message.ok
|
||||
|
||||
export { word }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Plugin } from 'yunzai/core'
|
||||
import fetch from 'node-fetch'
|
||||
import net from 'net'
|
||||
import fs from 'fs'
|
||||
import { readFileSync } from 'fs'
|
||||
import YAML from 'yaml'
|
||||
import { exec } from 'child_process'
|
||||
|
||||
|
@ -10,28 +10,31 @@ import { exec } from 'child_process'
|
|||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param port
|
||||
* @returns
|
||||
*
|
||||
* @param port
|
||||
* @returns
|
||||
*/
|
||||
const isPortTaken = async (port) => {
|
||||
return new Promise((resolve) => {
|
||||
const tester = net.createServer()
|
||||
const isPortTaken = async port => {
|
||||
return new Promise(resolve => {
|
||||
const tester = net
|
||||
.createServer()
|
||||
.once('error', () => resolve(true))
|
||||
.once('listening', () => tester.once('close', () => resolve(false)).close())
|
||||
.listen(port);
|
||||
});
|
||||
};
|
||||
.once('listening', () =>
|
||||
tester.once('close', () => resolve(false)).close()
|
||||
)
|
||||
.listen(port)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class Restart extends Plugin {
|
||||
key = 'Yz:restart'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param e
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
|
@ -57,7 +60,7 @@ export class Restart extends Plugin {
|
|||
async init() {
|
||||
const data = await redis.get(this.key)
|
||||
if (data) {
|
||||
const restart = JSON.parse(data)
|
||||
const restart = JSON.parse(data)
|
||||
const uin = restart?.uin || Bot.uin
|
||||
let time = restart.time || new Date().getTime()
|
||||
time = (new Date().getTime() - time) / 1000
|
||||
|
@ -80,9 +83,11 @@ export class Restart extends Plugin {
|
|||
async restart() {
|
||||
let restart_port
|
||||
try {
|
||||
restart_port = YAML.parse(fs.readFileSync(`./config/config/bot.yaml`, `utf-8`))
|
||||
restart_port = YAML.parse(
|
||||
readFileSync(`./config/config/bot.yaml`, `utf-8`)
|
||||
)
|
||||
restart_port = restart_port.restart_port || 27881
|
||||
} catch { }
|
||||
} catch {}
|
||||
await this.e.reply('开始执行重启,请稍等...')
|
||||
logger.mark(`${this.e.logFnc} 开始执行重启,请稍等...`)
|
||||
|
||||
|
@ -97,7 +102,9 @@ export class Restart extends Plugin {
|
|||
await redis.set(this.key, data, { EX: 120 })
|
||||
if (await isPortTaken(restart_port || 27881)) {
|
||||
try {
|
||||
const result = await fetch(`http://localhost:${restart_port || 27881}/restart`).then(res=>res.text())
|
||||
const result = await fetch(
|
||||
`http://localhost:${restart_port || 27881}/restart`
|
||||
).then(res => res.text())
|
||||
if (result !== `OK`) {
|
||||
redis.del(this.key)
|
||||
this.e.reply(`操作失败!`)
|
||||
|
@ -144,7 +151,7 @@ export class Restart extends Plugin {
|
|||
}
|
||||
|
||||
async execSync(cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(resolve => {
|
||||
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
|
||||
resolve({ error, stdout, stderr })
|
||||
})
|
||||
|
@ -154,9 +161,11 @@ export class Restart extends Plugin {
|
|||
async stop() {
|
||||
let restart_port
|
||||
try {
|
||||
restart_port = YAML.parse(fs.readFileSync(`./config/config/bot.yaml`, `utf-8`))
|
||||
restart_port = YAML.parse(
|
||||
readFileSync(`./config/config/bot.yaml`, `utf-8`)
|
||||
)
|
||||
restart_port = restart_port.restart_port || 27881
|
||||
} catch { }
|
||||
} catch {}
|
||||
if (await isPortTaken(restart_port || 27881)) {
|
||||
try {
|
||||
logger.mark('关机成功,已停止运行')
|
||||
|
@ -179,7 +188,7 @@ export class Restart extends Plugin {
|
|||
await this.e.reply('关机成功,已停止运行')
|
||||
|
||||
let npm = await this.checkPnpm()
|
||||
exec(`${npm} stop`, { windowsHide: true }, (error, stdout, stderr) => {
|
||||
exec(`${npm} stop`, { windowsHide: true }, error => {
|
||||
if (error) {
|
||||
this.e.reply(`操作失败!\n${error.stack}`)
|
||||
logger.error(`关机失败\n${error.stack}`)
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import { Plugin } from 'yunzai/core'
|
||||
import {makeForwardMsg} from 'yunzai/core'
|
||||
import fs from "node:fs"
|
||||
import lodash from "lodash"
|
||||
import moment from "moment"
|
||||
import { makeForwardMsg } from 'yunzai/core'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import lodash from 'lodash'
|
||||
import moment from 'moment'
|
||||
|
||||
/**
|
||||
* tudo
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class sendLog extends Plugin {
|
||||
lineNum = 100
|
||||
maxNum = 1000
|
||||
errFile = "logs/error.log"
|
||||
logFile = `logs/command.${moment().format("YYYY-MM-DD")}.log`
|
||||
errFile = 'logs/error.log'
|
||||
logFile = `logs/command.${moment().format('YYYY-MM-DD')}.log`
|
||||
keyWord = null
|
||||
constructor() {
|
||||
/**
|
||||
name: "发送日志",
|
||||
|
@ -26,65 +27,68 @@ export class sendLog extends Plugin {
|
|||
{
|
||||
reg: /^#(运行|错误)*日志[0-9]*(.*)/,
|
||||
fnc: this.sendLog.name,
|
||||
permission: "master"
|
||||
permission: 'master'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async sendLog() {
|
||||
let lineNum = this.e.msg.match(/\d+/g)
|
||||
if (lineNum) {
|
||||
this.lineNum = lineNum[0]
|
||||
this.lineNum = Number(lineNum[0])
|
||||
} else {
|
||||
this.keyWord = this.e.msg.replace(/#|运行|错误|日志|\d/g, "")
|
||||
this.keyWord = this.e.msg.replace(/#|运行|错误|日志|\d/g, '')
|
||||
}
|
||||
|
||||
let logFile = this.logFile
|
||||
let type = "运行"
|
||||
if (this.e.msg.includes("错误")) {
|
||||
let type = '运行'
|
||||
if (this.e.msg.includes('错误')) {
|
||||
logFile = this.errFile
|
||||
type = "错误"
|
||||
type = '错误'
|
||||
}
|
||||
|
||||
if (this.keyWord) type = this.keyWord
|
||||
|
||||
const log = this.getLog(logFile)
|
||||
|
||||
if (lodash.isEmpty(log))
|
||||
if (lodash.isEmpty(log)) {
|
||||
return this.reply(`暂无相关日志:${type}`)
|
||||
}
|
||||
|
||||
return this.reply(await makeForwardMsg(this.e, [log.join("\n")], `最近${log.length}条${type}日志`))
|
||||
const data = await makeForwardMsg(
|
||||
this.e,
|
||||
[log.join('\n')],
|
||||
`最近${log.length}条${type}日志`
|
||||
)
|
||||
return this.reply(data)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param logFile
|
||||
* @returns
|
||||
*
|
||||
* @param logFile
|
||||
* @returns
|
||||
*/
|
||||
getLog(logFile) {
|
||||
let log = fs.readFileSync(logFile, { encoding: "utf-8" })
|
||||
log = log.split("\n")
|
||||
const data = readFileSync(logFile, { encoding: 'utf-8' })
|
||||
let log = data.split('\n')
|
||||
|
||||
if (this.keyWord) {
|
||||
for (const i in log)
|
||||
if (!log[i].includes(this.keyWord))
|
||||
delete log[i]
|
||||
for (const i in log) if (!log[i].includes(this.keyWord)) delete log[i]
|
||||
} else {
|
||||
log = lodash.slice(log, (Number(this.lineNum) + 1) * -1)
|
||||
}
|
||||
log = log.reverse()
|
||||
|
||||
const tmp = []
|
||||
for (let i of log) {
|
||||
if (!i) continue
|
||||
if (this.keyWord && tmp.length >= this.maxNum) return
|
||||
/* eslint-disable no-control-regex */
|
||||
i = i.replace(/\x1b[[0-9;]*m/g, "")
|
||||
i = i.replace(/\r|\n/, "")
|
||||
i = i.replace(/\x1b[[0-9;]*m/g, '')
|
||||
i = i.replace(/\r|\n/, '')
|
||||
tmp.push(i)
|
||||
}
|
||||
return tmp
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import { ConfigController as cfg } from 'yunzai/config'
|
||||
import moment from 'moment'
|
||||
import { Plugin } from 'yunzai/core'
|
||||
|
@ -8,7 +7,7 @@ import { Plugin } from 'yunzai/core'
|
|||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class status extends Plugin {
|
||||
/**
|
||||
|
@ -26,8 +25,8 @@ export class status extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
async status() {
|
||||
if (this.e.isMaster) return this.statusMaster()
|
||||
|
@ -41,22 +40,27 @@ export class status extends Plugin {
|
|||
}
|
||||
|
||||
async statusMaster() {
|
||||
let runTime = moment().diff(moment.unix(this.e.bot.stat.start_time), 'seconds')
|
||||
let runTime = moment().diff(
|
||||
moment.unix(this.e.bot.stat.start_time),
|
||||
'seconds'
|
||||
)
|
||||
let Day = Math.floor(runTime / 3600 / 24)
|
||||
let Hour = Math.floor((runTime / 3600) % 24)
|
||||
let Min = Math.floor((runTime / 60) % 60)
|
||||
|
||||
let data = ''
|
||||
if (Day > 0) {
|
||||
runTime = `${Day}天${Hour}小时${Min}分钟`
|
||||
data = `${Day}天${Hour}小时${Min}分钟`
|
||||
} else {
|
||||
runTime = `${Hour}小时${Min}分钟`
|
||||
data = `${Hour}小时${Min}分钟`
|
||||
}
|
||||
|
||||
let format = (bytes) => {
|
||||
let format = bytes => {
|
||||
return (bytes / 1024 / 1024).toFixed(2) + 'MB'
|
||||
}
|
||||
|
||||
let msg = '-------状态-------'
|
||||
msg += `\n运行时间:${runTime}`
|
||||
msg += `\n运行时间:${data}`
|
||||
msg += `\n内存使用:${format(process.memoryUsage().rss)}`
|
||||
msg += `\n当前版本:v${cfg.package.version}`
|
||||
msg += '\n-------累计-------'
|
||||
|
@ -72,7 +76,13 @@ export class status extends Plugin {
|
|||
await this.e.reply(msg)
|
||||
}
|
||||
|
||||
async getCount(groupId:number | string = '') {
|
||||
date = null
|
||||
month = null
|
||||
key = null
|
||||
msgKey = null
|
||||
screenshotKey = null
|
||||
|
||||
async getCount(groupId: number | string = '') {
|
||||
this.date = moment().format('MMDD')
|
||||
this.month = Number(moment().month()) + 1
|
||||
|
||||
|
@ -100,22 +110,25 @@ export class status extends Plugin {
|
|||
let date = moment().startOf('week').add(i, 'days').format('MMDD')
|
||||
|
||||
week.msg += Number(await redis.get(`${this.msgKey.day}${date}`)) ?? 0
|
||||
week.screenshot += Number(await redis.get(`${this.screenshotKey.day}${date}`)) ?? 0
|
||||
week.screenshot +=
|
||||
Number(await redis.get(`${this.screenshotKey.day}${date}`)) ?? 0
|
||||
}
|
||||
|
||||
let count = {
|
||||
total: {
|
||||
msg: await redis.get(`${this.key}sendMsg:total`) || 0,
|
||||
screenshot: await redis.get(`${this.key}screenshot:total`) || 0
|
||||
msg: (await redis.get(`${this.key}sendMsg:total`)) || 0,
|
||||
screenshot: (await redis.get(`${this.key}screenshot:total`)) || 0
|
||||
},
|
||||
today: {
|
||||
msg: await redis.get(`${this.msgKey.day}${this.date}`) || 0,
|
||||
screenshot: await redis.get(`${this.screenshotKey.day}${this.date}`) || 0
|
||||
msg: (await redis.get(`${this.msgKey.day}${this.date}`)) || 0,
|
||||
screenshot:
|
||||
(await redis.get(`${this.screenshotKey.day}${this.date}`)) || 0
|
||||
},
|
||||
week,
|
||||
month: {
|
||||
msg: await redis.get(`${this.msgKey.month}${this.month}`) || 0,
|
||||
screenshot: await redis.get(`${this.screenshotKey.month}${this.month}`) || 0
|
||||
msg: (await redis.get(`${this.msgKey.month}${this.month}`)) || 0,
|
||||
screenshot:
|
||||
(await redis.get(`${this.screenshotKey.month}${this.month}`)) || 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,12 +141,12 @@ export class status extends Plugin {
|
|||
msg += `\n生成图片:${count.total.screenshot}次`
|
||||
}
|
||||
|
||||
if (count.month.msg > 200) {
|
||||
if (Number(count.month.msg) > 200) {
|
||||
msg += '\n-------本周-------'
|
||||
msg += `\n发送消息:${count.week.msg}条`
|
||||
msg += `\n生成图片:${count.week.screenshot}次`
|
||||
}
|
||||
if (moment().format('D') >= 8 && count.month.msg > 400) {
|
||||
if (Number(moment().format('D')) >= 8 && Number(count.month.msg) > 400) {
|
||||
msg += '\n-------本月-------'
|
||||
msg += `\n发送消息:${count.month.msg}条`
|
||||
msg += `\n生成图片:${count.month.screenshot}次`
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Plugin ,makeForwardMsg} from 'yunzai/core'
|
||||
import { Plugin, makeForwardMsg } from 'yunzai/core'
|
||||
import lodash from 'lodash'
|
||||
import fs from 'node:fs'
|
||||
import { existsSync, readdirSync } from 'node:fs'
|
||||
import { BOT_NAME } from 'yunzai/config'
|
||||
import { exec, execSync } from 'child_process'
|
||||
import { exec, execSync } from 'child_process'
|
||||
import { Restart } from './restart.js'
|
||||
import { sleep } from 'yunzai/utils'
|
||||
let uping = false
|
||||
|
@ -67,20 +67,24 @@ export class update extends Plugin {
|
|||
if (!plugin) return ''
|
||||
}
|
||||
|
||||
if (!fs.existsSync(`plugins/${plugin}/.git`)) return false
|
||||
if (!existsSync(`plugins/${plugin}/.git`)) return false
|
||||
|
||||
this.typeName = plugin
|
||||
return plugin
|
||||
}
|
||||
|
||||
async execSync(cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(resolve => {
|
||||
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
|
||||
resolve({ error, stdout, stderr })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
isUp = null
|
||||
isNowUp = null
|
||||
oldCommitId = null
|
||||
|
||||
async runUpdate(plugin = '') {
|
||||
this.isNowUp = false
|
||||
|
||||
|
@ -162,22 +166,26 @@ export class update extends Plugin {
|
|||
}
|
||||
|
||||
if (errMsg.includes('be overwritten by merge')) {
|
||||
return this.e.reply(`${msg}\n存在冲突:\n${errMsg}\n请解决冲突后再更新,或者执行#强制更新,放弃本地修改`)
|
||||
return this.e.reply(
|
||||
`${msg}\n存在冲突:\n${errMsg}\n请解决冲突后再更新,或者执行#强制更新,放弃本地修改`
|
||||
)
|
||||
}
|
||||
|
||||
if (stdout.includes('CONFLICT')) {
|
||||
return this.e.reply(`${msg}\n存在冲突:\n${errMsg}${stdout}\n请解决冲突后再更新,或者执行#强制更新,放弃本地修改`)
|
||||
return this.e.reply(
|
||||
`${msg}\n存在冲突:\n${errMsg}${stdout}\n请解决冲突后再更新,或者执行#强制更新,放弃本地修改`
|
||||
)
|
||||
}
|
||||
|
||||
return this.e.reply([errMsg, stdout])
|
||||
}
|
||||
|
||||
async updateAll() {
|
||||
const dirs = fs.readdirSync('./plugins/')
|
||||
const dirs = readdirSync('./plugins/')
|
||||
|
||||
const MSG = (message)=>{
|
||||
// 收集
|
||||
this.messages.push(message)
|
||||
const MSG = message => {
|
||||
// 收集
|
||||
this.messages.push(message)
|
||||
}
|
||||
|
||||
const testReg = /^#静默全部(强制)?更新$/.test(this.e.msg)
|
||||
|
@ -203,7 +211,6 @@ export class update extends Plugin {
|
|||
// await this.e.reply('即将执行重启,以应用更新')
|
||||
setTimeout(() => this.restart(), 2000)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
restart() {
|
||||
|
@ -243,13 +250,21 @@ export class update extends Plugin {
|
|||
cm = 'git config -l'
|
||||
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
|
||||
end = await execSync(cm, { encoding: 'utf-8' })
|
||||
end = end.match(/remote\..*\.url=.+/g).join('\n\n').replace(/remote\..*\.url=/g, '').replace(/\/\/([^@]+)@/, '//')
|
||||
end = end
|
||||
.match(/remote\..*\.url=.+/g)
|
||||
.join('\n\n')
|
||||
.replace(/remote\..*\.url=/g, '')
|
||||
.replace(/\/\/([^@]+)@/, '//')
|
||||
} catch (error) {
|
||||
logger.error(error.toString())
|
||||
await this.e.reply(error.toString())
|
||||
}
|
||||
|
||||
return makeForwardMsg(this.e, [log, end], `${plugin || 'Miao-Yunzai'} 更新日志,共${line}条`)
|
||||
return makeForwardMsg(
|
||||
this.e,
|
||||
[log, end],
|
||||
`${plugin || 'Miao-Yunzai'} 更新日志,共${line}条`
|
||||
)
|
||||
}
|
||||
|
||||
async updateLog() {
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export default function List({ children }) {
|
||||
return (
|
||||
<ul className="divide-y divide-slate-100">
|
||||
{children}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
return <ul className="divide-y divide-slate-100">{children}</ul>
|
||||
}
|
||||
|
|
|
@ -1,66 +1,87 @@
|
|||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export interface MovieType {
|
||||
id: number, //
|
||||
image:string, //
|
||||
title:string, // Prognosis Negative
|
||||
starRating: string, // 2.66
|
||||
rating:string, // PG-13
|
||||
year:string, // 2021
|
||||
genre:string, // Comedy
|
||||
runtime:string, // 1h 46m
|
||||
cast:string // Simon Pegg, Zach Galifianakis
|
||||
}
|
||||
id: number //
|
||||
image: string //
|
||||
title: string // Prognosis Negative
|
||||
starRating: string // 2.66
|
||||
rating: string // PG-13
|
||||
year: string // 2021
|
||||
genre: string // Comedy
|
||||
runtime: string // 1h 46m
|
||||
cast: string // Simon Pegg, Zach Galifianakis
|
||||
}
|
||||
|
||||
export default function ListItem({ movie }: {movie:MovieType}) {
|
||||
return (
|
||||
<article className="flex items-start space-x-6 p-6">
|
||||
<img src={movie.image} alt="" width="60" height="88" className="flex-none rounded-md bg-slate-100" />
|
||||
<div className="min-w-0 relative flex-auto">
|
||||
<h2 className="font-semibold text-slate-900 truncate pr-20">{movie.title}</h2>
|
||||
<dl className="mt-2 flex flex-wrap text-sm leading-6 font-medium">
|
||||
<div className="absolute top-0 right-0 flex items-center space-x-1">
|
||||
<dt className="text-sky-500">
|
||||
<span className="sr-only">Star rating</span>
|
||||
<svg width="16" height="20" fill="currentColor">
|
||||
<path d="M7.05 3.691c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.372 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.539 1.118l-2.8-2.034a1 1 0 00-1.176 0l-2.8 2.034c-.783.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.363-1.118L.98 9.483c-.784-.57-.381-1.81.587-1.81H5.03a1 1 0 00.95-.69L7.05 3.69z" />
|
||||
</svg>
|
||||
</dt>
|
||||
<dd>{movie.starRating}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Rating</dt>
|
||||
<dd className="px-1.5 ring-1 ring-slate-200 rounded">{movie.rating}</dd>
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
<dt className="sr-only">Year</dt>
|
||||
<dd>{movie.year}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Genre</dt>
|
||||
<dd className="flex items-center">
|
||||
<svg width="2" height="2" fill="currentColor" className="mx-2 text-slate-300" aria-hidden="true">
|
||||
<circle cx="1" cy="1" r="1" />
|
||||
</svg>
|
||||
{movie.genre}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Runtime</dt>
|
||||
<dd className="flex items-center">
|
||||
<svg width="2" height="2" fill="currentColor" className="mx-2 text-slate-300" aria-hidden="true">
|
||||
<circle cx="1" cy="1" r="1" />
|
||||
</svg>
|
||||
{movie.runtime}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex-none w-full mt-2 font-normal">
|
||||
<dt className="sr-only">Cast</dt>
|
||||
<dd className="text-slate-400">{movie.cast}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
export default function ListItem({ movie }: { movie: MovieType }) {
|
||||
return (
|
||||
<article className="flex items-start space-x-6 p-6">
|
||||
<img
|
||||
src={movie.image}
|
||||
alt=""
|
||||
width="60"
|
||||
height="88"
|
||||
className="flex-none rounded-md bg-slate-100"
|
||||
/>
|
||||
<div className="min-w-0 relative flex-auto">
|
||||
<h2 className="font-semibold text-slate-900 truncate pr-20">
|
||||
{movie.title}
|
||||
</h2>
|
||||
<dl className="mt-2 flex flex-wrap text-sm leading-6 font-medium">
|
||||
<div className="absolute top-0 right-0 flex items-center space-x-1">
|
||||
<dt className="text-sky-500">
|
||||
<span className="sr-only">Star rating</span>
|
||||
<svg width="16" height="20" fill="currentColor">
|
||||
<path d="M7.05 3.691c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.372 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.539 1.118l-2.8-2.034a1 1 0 00-1.176 0l-2.8 2.034c-.783.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.363-1.118L.98 9.483c-.784-.57-.381-1.81.587-1.81H5.03a1 1 0 00.95-.69L7.05 3.69z" />
|
||||
</svg>
|
||||
</dt>
|
||||
<dd>{movie.starRating}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Rating</dt>
|
||||
<dd className="px-1.5 ring-1 ring-slate-200 rounded">
|
||||
{movie.rating}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
<dt className="sr-only">Year</dt>
|
||||
<dd>{movie.year}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Genre</dt>
|
||||
<dd className="flex items-center">
|
||||
<svg
|
||||
width="2"
|
||||
height="2"
|
||||
fill="currentColor"
|
||||
className="mx-2 text-slate-300"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle cx="1" cy="1" r="1" />
|
||||
</svg>
|
||||
{movie.genre}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="sr-only">Runtime</dt>
|
||||
<dd className="flex items-center">
|
||||
<svg
|
||||
width="2"
|
||||
height="2"
|
||||
fill="currentColor"
|
||||
className="mx-2 text-slate-300"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle cx="1" cy="1" r="1" />
|
||||
</svg>
|
||||
{movie.runtime}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex-none w-full mt-2 font-normal">
|
||||
<dt className="sr-only">Cast</dt>
|
||||
<dd className="text-slate-400">{movie.cast}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import React from "react";
|
||||
import React from 'react'
|
||||
export default function Nav({ children }) {
|
||||
return (
|
||||
<nav className="py-4 px-6 text-sm font-medium">
|
||||
<ul className="flex space-x-3">
|
||||
{children}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<nav className="py-4 px-6 text-sm font-medium">
|
||||
<ul className="flex space-x-3">{children}</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React from "react";
|
||||
import React from 'react'
|
||||
export default function NavItem({ href, children }) {
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={href}
|
||||
className={`block px-3 py-2 rounded-md bg-sky-500 text-white`}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={href}
|
||||
className={`block px-3 py-2 rounded-md bg-sky-500 text-white`}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
2
data.ts
2
data.ts
|
@ -13,4 +13,4 @@ export const movies = [
|
|||
runtime: '1h 46m',
|
||||
cast: 'Simon Pegg, Zach Galifianakis '
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
52
image.tsx
52
image.tsx
|
@ -1,33 +1,33 @@
|
|||
import React from 'react'
|
||||
import { Picture } from 'yunzai/utils'
|
||||
import { createDynamic } from 'yunzai/utils'
|
||||
import { PropsType } from './views/hello.tsx'
|
||||
import { createDynamic } from 'yunzai/utils'
|
||||
const require = createDynamic(import.meta.url)
|
||||
export class Image extends Picture {
|
||||
constructor() {
|
||||
super()
|
||||
// start
|
||||
this.Pup.start()
|
||||
}
|
||||
/**
|
||||
* 为指定用户生成html 生成指定数据下的html文件
|
||||
* @param uid 用户编号
|
||||
* @param Props 组件参数
|
||||
* @returns
|
||||
*/
|
||||
async createHello(uid: number, Props: PropsType) {
|
||||
// 此作用域可被重复执行,此处将变成动态组件 - 这是危险的!
|
||||
const Hello = (await require('./views/hello.tsx')).default;
|
||||
// 生成 html 地址 或 html字符串
|
||||
const Address = this.Com.create(<Hello {...Props} />, {
|
||||
// html/hello/uid.html
|
||||
join_dir: 'hello',
|
||||
html_name: `${uid}.html`,
|
||||
})
|
||||
return this.Pup.render(Address, {
|
||||
tab: ''
|
||||
})
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
// start
|
||||
this.Pup.start()
|
||||
}
|
||||
/**
|
||||
* 为指定用户生成html 生成指定数据下的html文件
|
||||
* @param uid 用户编号
|
||||
* @param Props 组件参数
|
||||
* @returns
|
||||
*/
|
||||
async createHello(uid: number, Props: PropsType) {
|
||||
// 非生产环境将触发 动态组件效果
|
||||
const Hello = (
|
||||
await require('./views/hello.tsx', process.env.NODE_ENV != 'production')
|
||||
).default
|
||||
// 生成 html 地址 或 html字符串
|
||||
const Address = this.Com.create(<Hello {...Props} />, {
|
||||
// html/hello/uid.html
|
||||
join_dir: 'hello',
|
||||
html_name: `${uid}.html`
|
||||
})
|
||||
return this.Pup.render(Address)
|
||||
}
|
||||
}
|
||||
// 初始化 图片生成对象
|
||||
export const imgae = new Image()
|
||||
export const imgae = new Image()
|
||||
|
|
2
index.ts
2
index.ts
|
@ -1 +1 @@
|
|||
export * as apps from './apps/index.js'
|
||||
export * as apps from './apps/index.js'
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
{
|
||||
"name": "system-plugin",
|
||||
"type": "module",
|
||||
"scripts": {},
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
"scripts": {
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.0.3"
|
||||
}
|
||||
}
|
||||
|
|
16
routes.tsx
16
routes.tsx
|
@ -1,17 +1,17 @@
|
|||
import React from "react"
|
||||
import { movies } from "./data"
|
||||
import React from 'react'
|
||||
import { movies } from './data'
|
||||
import { createDynamic } from 'yunzai/utils'
|
||||
const require = createDynamic(import.meta.url)
|
||||
const Hello = (await require('./views/hello.tsx')).default;
|
||||
const Music = (await require('./views/music.tsx')).default;
|
||||
const Hello = (await require('./views/hello.tsx')).default
|
||||
const Music = (await require('./views/music.tsx')).default
|
||||
const Config = [
|
||||
{
|
||||
url: "/hello",
|
||||
element: <Hello data={{ name: "word" }} movies={movies} />
|
||||
url: '/hello',
|
||||
element: <Hello data={{ name: 'word' }} movies={movies} />
|
||||
},
|
||||
{
|
||||
url: "/music",
|
||||
url: '/music',
|
||||
element: <Music />
|
||||
}
|
||||
]
|
||||
export default Config
|
||||
export default Config
|
||||
|
|
8
tes.ts
8
tes.ts
|
@ -1,8 +0,0 @@
|
|||
|
||||
// const require = async (basePath: string) => {
|
||||
// const now = () => `?update=${Date.now()}`
|
||||
// return (await import(`${basePath}${now()}`))
|
||||
// }
|
||||
|
||||
// const Hello = await require('./views/hello.tsx')
|
||||
// const Music = await require(`./views/music.tsx`)
|
|
@ -18,22 +18,24 @@ const require = createRequire(import.meta.url)
|
|||
const url: string = require('../resources/example.png')
|
||||
|
||||
/**
|
||||
*
|
||||
* @param param0
|
||||
* @returns
|
||||
*
|
||||
* @param param0
|
||||
* @returns
|
||||
*/
|
||||
export default function App({ data, movies }: PropsType) {
|
||||
return (
|
||||
<div className="divide-y divide-slate-100 m-8 shadow-2xl">
|
||||
<img className='h-40 w-40' src={url}></img>
|
||||
<Nav>
|
||||
<NavItem href="./music" >New {data.name}</NavItem>
|
||||
</Nav>
|
||||
<List>
|
||||
{movies.map((movie) => (
|
||||
<ListItem key={movie.id} movie={movie} />
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
<section className="flex flex-col">
|
||||
<div className="divide-y divide-slate-100 m-8 shadow-2xl">
|
||||
<img className="h-40 w-40" src={url}></img>
|
||||
<Nav>
|
||||
<NavItem href="./music">New {data.name}</NavItem>
|
||||
</Nav>
|
||||
<List>
|
||||
{movies.map(movie => (
|
||||
<ListItem key={movie.id} movie={movie} />
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
236
views/music.tsx
236
views/music.tsx
|
@ -1,87 +1,171 @@
|
|||
import React from "react";
|
||||
import React from 'react'
|
||||
import { createRequire } from 'module'
|
||||
const require = createRequire(import.meta.url)
|
||||
const require = createRequire(import.meta.url)
|
||||
// 图片
|
||||
const url: string = require('../resources/example.png')
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export default function App() {
|
||||
return <>
|
||||
<div className="bg-white border-slate-100 dark:bg-slate-800 dark:border-slate-500 border-b rounded-t-xl p-4 pb-6 sm:p-10 sm:pb-8 lg:p-6 xl:p-10 xl:pb-8 space-y-6 sm:space-y-8 lg:space-y-6 xl:space-y-8">
|
||||
<div className="flex items-center space-x-4">
|
||||
<img src={url} alt="" width="88" height="88" className="flex-none rounded-lg bg-slate-100" loading="lazy" />
|
||||
<div className="min-w-0 flex-auto space-y-1 font-semibold">
|
||||
<p className="text-cyan-500 dark:text-cyan-400 text-sm leading-6">
|
||||
<abbr title="Episode">Ep.</abbr> 128
|
||||
</p>
|
||||
<h2 className="text-slate-500 dark:text-slate-400 text-sm leading-6 truncate">
|
||||
Scaling CSS at Heroku with Utility Classes
|
||||
</h2>
|
||||
<p className="text-slate-900 dark:text-slate-50 text-lg">
|
||||
Full Stack Radio
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="relative">
|
||||
<div className="bg-slate-100 dark:bg-slate-700 rounded-full overflow-hidden">
|
||||
<div className="bg-cyan-500 dark:bg-cyan-400 w-1/2 h-2" role="progressbar" ></div>
|
||||
</div>
|
||||
<div className="ring-cyan-500 dark:ring-cyan-400 ring-2 absolute left-1/2 top-1/2 w-4 h-4 -mt-2 -ml-2 flex items-center justify-center bg-white rounded-full shadow">
|
||||
<div className="w-1.5 h-1.5 bg-cyan-500 dark:bg-cyan-400 rounded-full ring-1 ring-inset ring-slate-900/5"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm leading-6 font-medium tabular-nums">
|
||||
<div className="text-cyan-500 dark:text-slate-100">24:16</div>
|
||||
<div className="text-slate-500 dark:text-slate-400">75:50</div>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<div className="bg-white border-slate-100 dark:bg-slate-800 dark:border-slate-500 border-b rounded-t-xl p-4 pb-6 sm:p-10 sm:pb-8 lg:p-6 xl:p-10 xl:pb-8 space-y-6 sm:space-y-8 lg:space-y-6 xl:space-y-8">
|
||||
<div className="flex items-center space-x-4">
|
||||
<img
|
||||
src={url}
|
||||
alt=""
|
||||
width="88"
|
||||
height="88"
|
||||
className="flex-none rounded-lg bg-slate-100"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="min-w-0 flex-auto space-y-1 font-semibold">
|
||||
<p className="text-cyan-500 dark:text-cyan-400 text-sm leading-6">
|
||||
<abbr title="Episode">Ep.</abbr> 128
|
||||
</p>
|
||||
<h2 className="text-slate-500 dark:text-slate-400 text-sm leading-6 truncate">
|
||||
Scaling CSS at Heroku with Utility Classes
|
||||
</h2>
|
||||
<p className="text-slate-900 dark:text-slate-50 text-lg">
|
||||
Full Stack Radio
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 text-slate-500 dark:bg-slate-600 dark:text-slate-200 rounded-b-xl flex items-center">
|
||||
<div className="flex-auto flex items-center justify-evenly">
|
||||
<button type="button" aria-label="Add to favorites">
|
||||
<svg width="24" height="24">
|
||||
<path d="M7 6.931C7 5.865 7.853 5 8.905 5h6.19C16.147 5 17 5.865 17 6.931V19l-5-4-5 4V6.931Z" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" className="hidden sm:block lg:hidden xl:block" aria-label="Previous">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path d="m10 12 8-6v12l-8-6Z" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M6 6v12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" aria-label="Rewind 10 seconds">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path d="M6.492 16.95c2.861 2.733 7.5 2.733 10.362 0 2.861-2.734 2.861-7.166 0-9.9-2.862-2.733-7.501-2.733-10.362 0A7.096 7.096 0 0 0 5.5 8.226" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M5 5v3.111c0 .491.398.889.889.889H9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<div className="space-y-2">
|
||||
<div className="relative">
|
||||
<div className="bg-slate-100 dark:bg-slate-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="bg-cyan-500 dark:bg-cyan-400 w-1/2 h-2"
|
||||
role="progressbar"
|
||||
></div>
|
||||
</div>
|
||||
<button type="button" className="bg-white text-slate-900 dark:bg-slate-100 dark:text-slate-700 flex-none -my-2 mx-auto w-20 h-20 rounded-full ring-1 ring-slate-900/5 shadow-md flex items-center justify-center" aria-label="Pause">
|
||||
<svg width="30" height="32" fill="currentColor">
|
||||
<rect x="6" y="4" width="4" height="24" rx="2" />
|
||||
<rect x="20" y="4" width="4" height="24" rx="2" />
|
||||
</svg>
|
||||
</button>
|
||||
<div className="flex-auto flex items-center justify-evenly">
|
||||
<button type="button" aria-label="Skip 10 seconds">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path d="M17.509 16.95c-2.862 2.733-7.501 2.733-10.363 0-2.861-2.734-2.861-7.166 0-9.9 2.862-2.733 7.501-2.733 10.363 0 .38.365.711.759.991 1.176" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M19 5v3.111c0 .491-.398.889-.889.889H15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" className="hidden sm:block lg:hidden xl:block" aria-label="Next">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path d="M14 12 6 6v12l8-6Z" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M18 6v12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" className="rounded-lg text-xs leading-6 font-semibold px-2 ring-2 ring-inset ring-slate-500 text-slate-500 dark:text-slate-100 dark:ring-0 dark:bg-slate-500">
|
||||
1x
|
||||
</button>
|
||||
<div className="ring-cyan-500 dark:ring-cyan-400 ring-2 absolute left-1/2 top-1/2 w-4 h-4 -mt-2 -ml-2 flex items-center justify-center bg-white rounded-full shadow">
|
||||
<div className="w-1.5 h-1.5 bg-cyan-500 dark:bg-cyan-400 rounded-full ring-1 ring-inset ring-slate-900/5"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between text-sm leading-6 font-medium tabular-nums">
|
||||
<div className="text-cyan-500 dark:text-slate-100">24:16</div>
|
||||
<div className="text-slate-500 dark:text-slate-400">75:50</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 text-slate-500 dark:bg-slate-600 dark:text-slate-200 rounded-b-xl flex items-center">
|
||||
<div className="flex-auto flex items-center justify-evenly">
|
||||
<button type="button" aria-label="Add to favorites">
|
||||
<svg width="24" height="24">
|
||||
<path
|
||||
d="M7 6.931C7 5.865 7.853 5 8.905 5h6.19C16.147 5 17 5.865 17 6.931V19l-5-4-5 4V6.931Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="hidden sm:block lg:hidden xl:block"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path
|
||||
d="m10 12 8-6v12l-8-6Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6 6v12"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" aria-label="Rewind 10 seconds">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path
|
||||
d="M6.492 16.95c2.861 2.733 7.5 2.733 10.362 0 2.861-2.734 2.861-7.166 0-9.9-2.862-2.733-7.501-2.733-10.362 0A7.096 7.096 0 0 0 5.5 8.226"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5 5v3.111c0 .491.398.889.889.889H9"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="bg-white text-slate-900 dark:bg-slate-100 dark:text-slate-700 flex-none -my-2 mx-auto w-20 h-20 rounded-full ring-1 ring-slate-900/5 shadow-md flex items-center justify-center"
|
||||
aria-label="Pause"
|
||||
>
|
||||
<svg width="30" height="32" fill="currentColor">
|
||||
<rect x="6" y="4" width="4" height="24" rx="2" />
|
||||
<rect x="20" y="4" width="4" height="24" rx="2" />
|
||||
</svg>
|
||||
</button>
|
||||
<div className="flex-auto flex items-center justify-evenly">
|
||||
<button type="button" aria-label="Skip 10 seconds">
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path
|
||||
d="M17.509 16.95c-2.862 2.733-7.501 2.733-10.363 0-2.861-2.734-2.861-7.166 0-9.9 2.862-2.733 7.501-2.733 10.363 0 .38.365.711.759.991 1.176"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M19 5v3.111c0 .491-.398.889-.889.889H15"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="hidden sm:block lg:hidden xl:block"
|
||||
aria-label="Next"
|
||||
>
|
||||
<svg width="24" height="24" fill="none">
|
||||
<path
|
||||
d="M14 12 6 6v12l8-6Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18 6v12"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-lg text-xs leading-6 font-semibold px-2 ring-2 ring-inset ring-slate-500 text-slate-500 dark:text-slate-100 dark:ring-0 dark:bg-slate-500"
|
||||
>
|
||||
1x
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue