UNPKG

yunzai-micro-plugin

Version:

Yunzai开发管理面板

347 lines (344 loc) 10.7 kB
import crypto from 'crypto'; import fs from 'fs'; import get_urls from 'get-urls'; import fetch from 'node-fetch'; import { join, dirname } from 'path'; import '../../../../utils/index.js'; import { pluginInfo } from '../../../../env.js'; import Stdlog from '../../../../utils/stdlog.js'; if (!Bot?.adapter) { Bot.adapter = Bot.uin ? [Bot.uin] : []; } else { if (!Bot.adapter.includes(Bot.uin)) { Bot.adapter.push(Bot.uin); } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function init(key = 'micro:restart') { let restart = await redis.get(key); if (!restart) return; redis.del(key); restart = JSON.parse(restart); const uin = restart?.uin || Bot.uin; const time = (Date.now() - (restart.time || Date.now())) / 1000; const msgId = restart?.msg_id || false; let restartMsg = `重启成功:耗时${time.toFixed(2)}秒`; let msg; if (restart?.adapter === 'QQBot' && msgId) msg = [{ type: 'reply', id: msgId }, restartMsg]; try { if (restart.isGroup) { Bot[uin].pickGroup(restart.id, msgId).sendMsg(msg); } else { Bot[uin].pickUser(restart.id).sendMsg(msg); } } catch (error) { } } function array(data) { let msg = []; if (typeof data === 'object' && data?.test && data?.data?.type === 'test') return data.message; if (data?.[0]?.data?.type === 'test' || data?.[1]?.data?.type === 'test') { msg.push(...(data?.[0].msg || data?.[1].msg)); } else if (data?.data?.type === 'test') { msg.push(...data.msg); } else if (Array.isArray(data)) { msg = [].concat(...data.map(i => (typeof i === 'string' ? [{ type: 'text', text: i }] : Array.isArray(i) ? [].concat(...i.map(format => (typeof format === 'string' ? [{ type: 'text', text: format }] : typeof format === 'object' && format !== null ? [format] : []))) : typeof i === 'object' && i !== null ? [i] : []))); } else if (data instanceof fs.ReadStream) { if (fs.existsSync(data.file.path)) { msg.push({ type: 'image', file: `file://${data.file.path}` }); } else { msg.push({ type: 'image', file: `file://./${data.file.path}` }); } } else if (data instanceof Uint8Array) { msg.push({ type: 'image', file: data }); } else if (typeof data === 'object') { msg.push(data); } else { msg.push({ type: 'text', text: data }); } return msg; } async function makeForwardMsg(data, node = false, e = {}) { const message = { type: 'forward' }; let allMsg = []; if (!Array.isArray(data)) data = [data]; for (let i = 0; i < data.length; i++) { let msg = data[i].message; if (typeof msg === 'object' && (msg?.data?.type === 'test' || msg?.type === 'xml')) { data.splice(i, 1, ...msg.msg); i--; } } for (let msg in data) { msg = data[msg]?.message || data[msg]; if (!msg && msg?.type) continue; if (Array.isArray(msg)) { msg.forEach(i => { if (typeof i === 'string') { allMsg.push('\n' + i.trim()); } else { allMsg.push(i); } }); } else if (typeof msg === 'object' && /^#.*日志$/.test(e?.msg?.content)) { if (msg) { const splitMsg = msg.split('\n').map(i => { if (!i || i.trim() === '') return {}; return '\n' + i.substring(0, 500).trim(); }); allMsg.push(...splitMsg.slice(0, 50)); } } else if (typeof msg === 'object') { allMsg.push(msg); } else if (typeof msg === 'string') { allMsg.push('\n' + msg); } else { Stdlog.warn('', '未兼容的字段:', msg); } } if (node) allMsg.forEach(i => { i.node = true; }); message.text = Array.from(new Set(allMsg.map((item) => JSON.stringify(item)))).map(item => JSON.parse(item)); message.data = { type: 'forward', text: 'text', app: 'com.tencent.multimsg', meta: { detail: { news: [{ text: '1' }] }, resid: '', uniseq: '', summary: '' } }; return message; } async function base64(path) { let file = path; try { if (!fs.existsSync(file)) { file = file.replace(/^file:\/\//, ''); if (!fs.existsSync(file)) { file = path.replace(/^file:\/\/\//, ''); if (!fs.existsSync(file)) return; } } return fs.readFileSync(file, { encoding: 'base64' }); } catch (err) { } } async function uploadQQ(file, uin = Bot.uin) { let base64; if (Buffer.isBuffer(file)) { base64 = file.toString('base64'); } else if (file.startsWith('file://')) { base64 = fs.readFileSync(file.slice(7)).toString('base64'); } else if (!file.startsWith('base64://') && fs.existsSync(file)) { base64 = fs.readFileSync(file).toString('base64'); } else if (file.startsWith('base64://')) { base64 = file.slice(9); } else { throw new Error('上传失败,未知格式的文件'); } try { const { message_id } = await Bot[uin].pickUser(uin).sendMsg([segment.image(`base64://${base64}`)]); await Bot[uin].pickUser(uin).recallMsg(message_id); } catch { } const md5 = crypto.createHash('md5').update(Buffer.from(base64, 'base64')).digest('hex'); return `https://gchat.qpic.cn/gchatpic_new/0/0-0-${md5.toUpperCase()}/0?term=2&is_origin=0`; } function getUrls(url, exclude = []) { let urls = []; url = url.replace(/[\u4e00-\u9fa5]/g, '|'); try { urls = [...get_urls(url, { exclude, stripWWW: false, normalizeProtocol: false, removeQueryParameters: false, removeSingleSlash: false, sortQueryParameters: false, stripAuthentication: false, stripTextFragment: false, removeTrailingSlash: false })]; } catch { Stdlog.info('Micro-plugin', '没有安装 get-urls 模块,建议执行pnpm install'); const urlRegex = /(https?:\/\/)?(([0-9a-z.-]+\.[a-z]+)|(([0-9]{1,3}\.){3}[0-9]{1,3}))(:[0-9]+)?(\/[0-9a-z%/.\-_#]*)?(\?[0-9a-z=&%_\-.]*)?(\\#[0-9a-z=&%_\\-]*)?/ig; urls = url.match(urlRegex); if (!urls) urls = []; return urls; } return urls; } function message_id() { return Buffer.from(Date.now().toString()).toString('base64'); } function mkdirs(dirname) { if (fs.existsSync(dirname)) { return true; } else { if (mkdirs(dirname(dirname))) { fs.mkdirSync(dirname); return true; } } } async function downloadFile(url, destPath, headers = {}, absolute = false) { let response = await fetch(url, { headers }); if (!response.ok) { throw new Error(`download file http error: status: ${response.status}`); } let dest = destPath; if (!absolute) { dest = join(pluginInfo.DATA_PATH, dest); const lastLevelDirPath = dirname(dest); mkdirs(lastLevelDirPath); } const fileStream = fs.createWriteStream(dest); await new Promise((resolve, reject) => { response.body.pipe(fileStream); response.body.on('error', err => { reject(err); }); fileStream.on('finish', function () { resolve('ok'); }); }); Stdlog.info('', `File downloaded successfully! URL: ${url}, Destination: ${dest}`); return dest; } function getFile(i) { if (i?.url) { if (i?.url?.includes('gchat.qpic.cn') && !i?.url?.startsWith('https://')) { i = 'https://' + i.url; } else { i = i.url; } } else if (typeof i === 'object') { i = i.file; } let file; let type = 'file'; if (i?.type === 'Buffer') { type = 'buffer'; file = Buffer.from(i?.data); } else if (i?.type === 'Buffer' || i instanceof Uint8Array || Buffer.isBuffer(i?.data || i)) { type = 'buffer'; file = i?.data || i; } else if (i instanceof fs.ReadStream || i?.path) { if (fs.existsSync(i.path)) { file = `file://${i.path}`; } else { file = `file://./${i.path}`; } } else if (typeof i === 'string') { if (fs.existsSync(i.replace(/^file:\/\//, ''))) { file = i; } else if (fs.existsSync(i.replace(/^file:\/\/\//, ''))) { file = i.replace(/^file:\/\/\//, 'file://'); } else if (fs.existsSync(i)) { file = `file://${i}`; } else if (/^base64:\/\//.test(i)) { type = 'base64'; file = i; } else if (/^http(s)?:\/\//.test(i)) { type = 'http'; file = i; } else { Stdlog.info('Micro-ws', '未知格式,无法处理:', i); type = 'error'; file = i; } } else { Stdlog.info('Micro-ws', '未知格式,无法处理:', i); type = 'error'; file = i; } return { type, file }; } async function recvMsg(id, adapter, read = false) { const key = `micro:recvMsg:${adapter}:${id}`; if (read) { const msg = await redis.get(key); return msg || 0; } await redis.incr(key); } async function MsgTotal(id, adapter, type = 'text', read = false) { const key = `micro:sendMsg:${adapter}:${id}:${type === 'text' ? 'text' : 'image'}`; if (read) { const msg = await redis.get(key); return msg || 0; } await redis.incr(key); } function limitString(str, maxLength, addDots = true) { if (str.length <= maxLength) { return str; } else { if (addDots) { return str.slice(0, maxLength) + '...'; } else { return str.slice(0, maxLength); } } } var common = { sleep, array, makeForwardMsg, base64, uploadQQ, getUrls, init, message_id, downloadFile, mkdirs, getFile, recvMsg, MsgTotal, limitString }; export { common as default };