UNPKG

n8n-nodes-onebot-api

Version:

OneBot node for n8n workflow, now you can send message to your QQ friend or group. This version includes optimized group and private chat operations and enhanced permission grading. OneBot 节点用于 n8n 工作流,现在您可以向您的 QQ 朋友或群组发送消息。此版本包括优化的群聊和私聊操作以及增强的权限分级。

640 lines 32.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeMessageOperation = void 0; const GenericFunctions_1 = require("./GenericFunctions"); async function executeMessageOperation(index) { const operation = this.getNodeParameter('operation', index); console.log(`执行消息操作: ${operation}`); if (operation === 'send_private_msg') { return await handlePrivateMessage.call(this, index); } else if (operation === 'send_group_msg') { return await handleGroupMessage.call(this, index); } else { throw new Error(`未知的消息操作:${operation}`); } } exports.executeMessageOperation = executeMessageOperation; function processBase64Image(base64Data) { if (!base64Data || base64Data.trim() === '') { console.log('Base64数据为空'); return ''; } const sizeInBytes = Math.ceil((base64Data.length * 3) / 4); const sizeInMB = sizeInBytes / (1024 * 1024); console.log(`Base64图片大小: ${sizeInMB.toFixed(2)}MB`); if (sizeInMB > 10) { console.log(`警告: Base64图片较大 (${sizeInMB.toFixed(2)}MB),可能导致发送延迟或超时`); } let cleanedData = base64Data; if (cleanedData.includes('base64,')) { cleanedData = cleanedData.split('base64,')[1]; } const base64Regex = /^[A-Za-z0-9+/=]+$/; if (!base64Regex.test(cleanedData)) { console.log('Base64数据包含无效字符'); throw new Error('无效的Base64图片数据'); } return `base64://${cleanedData}`; } function detectAndProcessBase64InMessage(message, autoDetect = false) { if (!message || message.trim() === '' || !autoDetect) { return message; } if (message.includes('[CQ:')) { return message; } try { const trimmedMessage = message.trim(); if (trimmedMessage.length >= 100 && /^[A-Za-z0-9+/=]+$/.test(trimmedMessage) && !/\s{2,}/.test(trimmedMessage) && !/[\u4e00-\u9fa5]|^(http|www|\w+\s\w+)/.test(trimmedMessage)) { try { console.log('检测到可能的Base64图片数据,尝试转换为CQ码'); const processedBase64 = processBase64Image(trimmedMessage); if (processedBase64) { return `[CQ:image,file=${processedBase64}]`; } } catch (error) { console.log('Base64转换失败,保留原始文本', error); } } return message; } catch (error) { console.log('Base64检测处理出错,保留原始消息:', error); return message; } } async function handlePrivateMessage(index) { const privateUserId = this.getNodeParameter('user_id', index); const body = { user_id: privateUserId }; let endpoint = ''; const privateForwardMode = this.getNodeParameter('forward_mode', index, false); if (privateForwardMode) { const forwardMessages = this.getNodeParameter('forwardMessages', index); const forwardSettings = this.getNodeParameter('forwardSettings', index, {}); let newsItems = []; try { const newsMessages = this.getNodeParameter('newsMessages', index, { news: [] }); if (newsMessages.news && newsMessages.news.length > 0) { newsItems = newsMessages.news.map(item => ({ text: item.text })); console.log('使用旧版newsMessages参数'); } } catch (e) { console.log('获取旧版newsMessages参数失败:', e instanceof Error ? e.message : String(e)); } const messages = forwardMessages.messages.map(msg => { let content = msg.content || ''; if (msg.addImage) { try { let imagePath = ''; const imageSource = msg.imageSource || 'url'; if (imageSource === 'url') { imagePath = msg.imageUrl || ''; } else if (imageSource === 'file') { const filePath = msg.imagePath || ''; imagePath = filePath ? 'file://' + filePath : ''; } else if (imageSource === 'base64') { try { imagePath = processBase64Image(msg.imageBase64 || ''); } catch (e) { console.error('处理Base64图片失败:', e instanceof Error ? e.message : String(e)); } } if (imagePath && imagePath.trim() !== '') { content = `[CQ:image,file=${imagePath}]`; } else { console.log('转发消息中图片路径为空,跳过添加图片'); } } catch (error) { console.error('处理转发消息图片时出错:', error instanceof Error ? error.message : String(error)); } } const userId = msg.user_id && msg.user_id.trim() !== '' ? msg.user_id : '10000'; const nickname = msg.nickname && msg.nickname.trim() !== '' ? msg.nickname : '用户'; return { type: 'node', data: { user_id: userId, nickname: nickname, content } }; }); body.messages = messages; if (forwardSettings.summary) body.summary = forwardSettings.summary; if (forwardSettings.prompt) body.prompt = forwardSettings.prompt; if (forwardSettings.source) body.source = forwardSettings.source; if (forwardSettings.news) { body.news = [{ text: forwardSettings.news }]; console.log(`使用forwardSettings.news参数: ${forwardSettings.news}`); } else if (newsItems.length > 0) { body.news = newsItems; console.log(`使用旧版newsMessages参数,包含${newsItems.length}条内容`); } else { body.news = [{ text: "查看详细内容" }]; } endpoint = 'send_private_forward_msg'; console.log('send_private_forward_msg参数:', JSON.stringify(body)); } else { let privateMessageContent = this.getNodeParameter('message', index); const autoDetectBase64 = false; privateMessageContent = detectAndProcessBase64InMessage(privateMessageContent, autoDetectBase64); const privateSendImage = this.getNodeParameter('sendImage', index, false); if (privateSendImage) { try { console.log(`[私聊消息] 发送图片标志为true,开始处理图片`); const imageSource = this.getNodeParameter('imageSource', index, 'url'); console.log(`[私聊消息] 图片来源: ${imageSource}`); let imagePath = ''; if (imageSource === 'url') { imagePath = this.getNodeParameter('imageUrl', index, ''); console.log(`[私聊消息] 图片URL: ${imagePath}`); } else if (imageSource === 'file') { const filePath = this.getNodeParameter('imagePath', index, ''); console.log(`[私聊消息] 本地图片路径: ${filePath}`); imagePath = filePath ? 'file://' + filePath : ''; } else if (imageSource === 'base64') { try { const base64Data = this.getNodeParameter('imageBase64', index, ''); console.log(`[私聊消息] Base64图片数据长度: ${base64Data.length}`); imagePath = processBase64Image(base64Data); } catch (e) { console.error('[私聊消息] 处理Base64图片失败:', e instanceof Error ? e.message : String(e)); throw e; } } if (imagePath && imagePath.trim() !== '') { console.log(`[私聊消息] 图片路径有效,添加图片CQ码`); if (!privateMessageContent.trim()) { privateMessageContent = `[CQ:image,file=${imagePath}]`; } else { privateMessageContent = `${privateMessageContent}\n[CQ:image,file=${imagePath}]`; } } else { console.log('[私聊消息] 图片路径为空,跳过添加图片CQ码'); } } catch (error) { console.error('[私聊消息] 处理图片时出错:', error instanceof Error ? error.message : String(error)); throw error; } } body.message = privateMessageContent; endpoint = 'send_private_msg'; console.log('send_private_msg参数:', JSON.stringify(body)); } try { const data = await GenericFunctions_1.apiRequest.call(this, 'POST', endpoint, body); return { json: data }; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); if (errorMsg.includes('aborted') || errorMsg.includes('connection')) { throw new Error(`发送私聊消息失败: 服务器连接中断。请求未成功完成,消息未发送。可能原因:图片太大或格式有问题,请尝试使用更小的图片或检查网络连接。`); } else if (errorMsg.includes('timeout') || errorMsg.includes('timed out')) { throw new Error(`发送私聊消息失败: 请求超时。请求未成功完成,消息未发送。请检查网络连接和服务器状态后重试。`); } throw error; } } async function handleGroupMessage(index) { try { let groupId; try { groupId = this.getNodeParameter('group_id', index); console.log(`成功获取群ID: ${groupId}`); } catch (error) { console.error('获取群ID参数失败:', error instanceof Error ? error.message : String(error)); throw new Error('发送群消息失败: 无法获取群ID参数'); } if (!groupId) { throw new Error('发送群消息需要有效的群ID,但未提供'); } const body = { group_id: groupId }; let endpoint = ''; let groupForwardMode = false; try { groupForwardMode = this.getNodeParameter('forward_mode', index, false); console.log(`转发模式: ${groupForwardMode ? '启用' : '禁用'}`); } catch (error) { console.error('获取转发模式参数失败:', error instanceof Error ? error.message : String(error)); groupForwardMode = false; } if (groupForwardMode) { let forwardMessages = { messages: [] }; try { forwardMessages = this.getNodeParameter('forwardMessages', index); console.log(`获取到转发消息列表,包含${forwardMessages.messages.length}条消息`); } catch (error) { console.error('获取转发消息列表参数失败:', error instanceof Error ? error.message : String(error)); console.log('将根据输入数据自动创建转发消息'); try { const loginInfoResponse = await GenericFunctions_1.apiRequest.call(this, 'GET', 'get_login_info'); if (loginInfoResponse && loginInfoResponse.data) { const botInfo = loginInfoResponse.data; let content = ''; let hasImage = false; let imageUrl = ''; try { const inputData = this.getInputData(); if (inputData && inputData[index]) { const jsonData = inputData[index].json; if (jsonData) { if (typeof jsonData.message === 'string') { content = jsonData.message; } else if (typeof jsonData.text === 'string') { content = jsonData.text; } else if (typeof jsonData.content === 'string') { content = jsonData.content; } else if (typeof jsonData.data === 'string') { content = jsonData.data; } else if (jsonData.message !== undefined) { content = String(jsonData.message); } else if (jsonData.text !== undefined) { content = String(jsonData.text); } else if (jsonData.content !== undefined) { content = String(jsonData.content); } else if (jsonData.data !== undefined) { content = String(jsonData.data); } if (typeof jsonData.imageUrl === 'string') { imageUrl = jsonData.imageUrl; hasImage = true; } else if (typeof jsonData.url === 'string' && (jsonData.url.endsWith('.jpg') || jsonData.url.endsWith('.jpeg') || jsonData.url.endsWith('.png') || jsonData.url.endsWith('.gif'))) { imageUrl = jsonData.url; hasImage = true; } } if (inputData[index].binary && typeof inputData[index].binary === 'object') { const binaryData = inputData[index].binary; if (binaryData && Object.keys(binaryData).length > 0) { for (const binaryPropertyName of Object.keys(binaryData)) { const binaryProperty = binaryData[binaryPropertyName]; if (binaryProperty && binaryProperty.mimeType && binaryProperty.mimeType.startsWith('image/')) { imageUrl = `base64://${binaryProperty.data}`; hasImage = true; break; } } } } } } catch (inputError) { console.error('从输入数据获取内容失败:', inputError instanceof Error ? inputError.message : String(inputError)); } if (!content && !hasImage) { content = '转发的消息'; } forwardMessages = { messages: [ { user_id: botInfo.user_id.toString(), nickname: botInfo.nickname || '机器人', addImage: hasImage, imageSource: hasImage ? (imageUrl.startsWith('base64://') ? 'base64' : 'url') : undefined, imageUrl: hasImage && !imageUrl.startsWith('base64://') ? imageUrl : undefined, imageBase64: hasImage && imageUrl.startsWith('base64://') ? imageUrl.replace('base64://', '') : undefined, content: content || '转发的消息' } ] }; console.log('自动创建了转发消息,使用机器人信息'); } else { console.error('无法获取机器人信息,使用默认值'); forwardMessages = { messages: [ { user_id: '10000', nickname: '机器人', addImage: false, content: '转发的消息' } ] }; } } catch (botInfoError) { console.error('获取机器人信息失败:', botInfoError instanceof Error ? botInfoError.message : String(botInfoError)); forwardMessages = { messages: [ { user_id: '10000', nickname: '机器人', addImage: false, content: '转发的消息' } ] }; } } let forwardSettings = {}; try { forwardSettings = this.getNodeParameter('forwardSettings', index, {}); console.log('成功获取转发设置参数'); } catch (error) { console.error('获取转发设置参数失败:', error instanceof Error ? error.message : String(error)); forwardSettings = {}; } let newsItems = []; try { const newsMessages = this.getNodeParameter('newsMessages', index, { news: [] }); if (newsMessages.news && newsMessages.news.length > 0) { newsItems = newsMessages.news.map(item => ({ text: item.text })); console.log('使用旧版newsMessages参数'); } } catch (error) { console.log('获取旧版newsMessages参数失败:', error instanceof Error ? error.message : String(error)); } const messages = forwardMessages.messages.map(msg => { let content = ''; if (msg.addImage) { try { let imagePath = ''; const imageSource = msg.imageSource || 'url'; if (imageSource === 'url') { imagePath = msg.imageUrl || ''; } else if (imageSource === 'file') { const filePath = msg.imagePath || ''; imagePath = filePath ? 'file://' + filePath : ''; } else if (imageSource === 'base64') { try { imagePath = processBase64Image(msg.imageBase64 || ''); } catch (e) { console.error('处理Base64图片失败:', e instanceof Error ? e.message : String(e)); } } if (imagePath && imagePath.trim() !== '') { content = `[CQ:image,file=${imagePath}]`; } else { console.log('群聊转发消息中图片路径为空,跳过添加图片'); } } catch (error) { console.error('处理群聊转发消息图片时出错:', error instanceof Error ? error.message : String(error)); } } const userId = msg.user_id && msg.user_id.trim() !== '' ? msg.user_id : '10000'; const nickname = msg.nickname && msg.nickname.trim() !== '' ? msg.nickname : '用户'; return { type: 'node', data: { user_id: userId, nickname: nickname, content } }; }); body.messages = messages; if (forwardSettings.summary) body.summary = forwardSettings.summary; if (forwardSettings.prompt) body.prompt = forwardSettings.prompt; if (forwardSettings.source) body.source = forwardSettings.source; if (forwardSettings.news) { body.news = [{ text: forwardSettings.news }]; console.log(`使用forwardSettings.news参数: ${forwardSettings.news}`); } else if (newsItems.length > 0) { body.news = newsItems; console.log(`使用旧版newsMessages参数,包含${newsItems.length}条内容`); } else { body.news = [{ text: "查看详细内容" }]; } endpoint = 'send_group_forward_msg'; console.log('send_group_forward_msg参数:', JSON.stringify(body)); } else { let messageContent = ''; try { messageContent = this.getNodeParameter('message', index); console.log('成功获取消息内容参数'); } catch (error) { console.error('获取消息内容参数失败:', error instanceof Error ? error.message : String(error)); try { const inputData = this.getInputData(); if (inputData && inputData[index] && inputData[index].json) { const jsonData = inputData[index].json; if (typeof jsonData.message === 'string') { messageContent = jsonData.message; console.log('从输入数据中获取消息内容'); } else if (typeof jsonData.text === 'string') { messageContent = jsonData.text; console.log('从输入数据text字段获取消息内容'); } else if (typeof jsonData.content === 'string') { messageContent = jsonData.content; console.log('从输入数据content字段获取消息内容'); } else { messageContent = '消息内容为空'; console.log('无法获取消息内容,使用默认值'); } } else { messageContent = '消息内容为空'; console.log('输入数据为空,使用默认消息内容'); } } catch (inputError) { console.error('尝试从输入数据获取消息内容失败:', inputError instanceof Error ? inputError.message : String(inputError)); messageContent = '消息内容为空'; } } const autoDetectBase64 = false; messageContent = detectAndProcessBase64InMessage(messageContent, autoDetectBase64); let atAll = false; try { atAll = this.getNodeParameter('atAll', index, false); console.log(`@全体成员: ${atAll ? '是' : '否'}`); } catch (error) { console.error('获取@全体成员参数失败:', error instanceof Error ? error.message : String(error)); atAll = false; } if (atAll) { messageContent = '[CQ:at,qq=all] ' + messageContent; } let atUser = false; try { atUser = this.getNodeParameter('atUser', index, false); console.log(`@特定成员: ${atUser ? '是' : '否'}`); } catch (error) { console.error('获取@特定成员参数失败:', error instanceof Error ? error.message : String(error)); atUser = false; } if (atUser) { let atUserId = ''; try { atUserId = this.getNodeParameter('atUserId', index); console.log(`@用户ID: ${atUserId}`); } catch (error) { console.error('获取@用户ID参数失败:', error instanceof Error ? error.message : String(error)); atUserId = ''; } if (atUserId) { messageContent = `[CQ:at,qq=${atUserId}] ${messageContent}`; } } let sendImage = false; try { sendImage = this.getNodeParameter('sendImage', index, false); console.log(`发送图片: ${sendImage ? '是' : '否'}`); } catch (error) { console.error('获取发送图片参数失败:', error instanceof Error ? error.message : String(error)); sendImage = false; } if (sendImage) { try { console.log(`[群聊消息] 发送图片标志为true,开始处理图片`); let imageSource = 'url'; try { imageSource = this.getNodeParameter('imageSource', index, 'url'); console.log(`[群聊消息] 图片来源: ${imageSource}`); } catch (error) { console.error('获取图片来源参数失败:', error instanceof Error ? error.message : String(error)); imageSource = 'url'; } let imagePath = ''; if (imageSource === 'url') { try { imagePath = this.getNodeParameter('imageUrl', index, ''); console.log(`[群聊消息] 图片URL: ${imagePath}`); } catch (error) { console.error('获取图片URL参数失败:', error instanceof Error ? error.message : String(error)); imagePath = ''; } } else if (imageSource === 'file') { let filePath = ''; try { filePath = this.getNodeParameter('imagePath', index, ''); console.log(`[群聊消息] 本地图片路径: ${filePath}`); } catch (error) { console.error('获取本地图片路径参数失败:', error instanceof Error ? error.message : String(error)); filePath = ''; } imagePath = filePath ? 'file://' + filePath : ''; } else if (imageSource === 'base64') { try { let base64Data = ''; try { base64Data = this.getNodeParameter('imageBase64', index, ''); console.log(`[群聊消息] Base64图片数据长度: ${base64Data.length}`); } catch (error) { console.error('获取Base64图片数据参数失败:', error instanceof Error ? error.message : String(error)); base64Data = ''; } if (base64Data && base64Data.trim() !== '') { imagePath = processBase64Image(base64Data); } } catch (e) { console.error('[群聊消息] 处理Base64图片失败:', e instanceof Error ? e.message : String(e)); } } if (imagePath && imagePath.trim() !== '') { console.log(`[群聊消息] 图片路径有效,添加图片CQ码`); if (!messageContent.trim()) { messageContent = `[CQ:image,file=${imagePath}]`; } else if (messageContent.trim() === '[CQ:at,qq=all] ') { messageContent = `[CQ:at,qq=all] [CQ:image,file=${imagePath}]`; } else if (messageContent.includes('[CQ:at,qq=') && !messageContent.includes('[CQ:at,qq=all]')) { messageContent = `${messageContent}[CQ:image,file=${imagePath}]`; } else { messageContent = `${messageContent}\n[CQ:image,file=${imagePath}]`; } } else { console.log('[群聊消息] 图片路径为空,跳过添加图片CQ码'); } } catch (error) { console.error('[群聊消息] 处理群聊图片时出错,但继续执行:', error instanceof Error ? error.message : String(error)); } } body.message = messageContent; endpoint = 'send_group_msg'; console.log('send_group_msg参数:', JSON.stringify(body)); } try { const data = await GenericFunctions_1.apiRequest.call(this, 'POST', endpoint, body); return { json: data }; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); if (errorMsg.includes('aborted') || errorMsg.includes('connection')) { throw new Error(`发送群消息失败: 服务器连接中断。请求未成功完成,消息未发送。可能原因:图片太大或格式有问题,请尝试使用更小的图片或检查网络连接。`); } else if (errorMsg.includes('timeout') || errorMsg.includes('timed out')) { throw new Error(`发送群消息失败: 请求超时。请求未成功完成,消息未发送。请检查网络连接和服务器状态后重试。`); } throw error; } } catch (outerError) { console.error('执行群聊消息操作时出错:', outerError instanceof Error ? outerError.message : String(outerError)); throw outerError; } } //# sourceMappingURL=MessageActions.js.map