From 6ff49722d8c9a50fdef131e76ae8359f0b2d5f8a Mon Sep 17 00:00:00 2001 From: student_2333 Date: Tue, 30 Apr 2024 12:50:38 +0800 Subject: [PATCH 1/5] feat: music card sign --- src/common/config.ts | 1 + src/common/types.ts | 1 + src/common/utils/sign.ts | 35 ++++++++++++++++++++++++++++++ src/onebot11/action/msg/SendMsg.ts | 32 ++++++++++++++++++--------- src/onebot11/types.ts | 18 ++++++++------- src/renderer/index.ts | 14 ++++++++++-- 6 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 src/common/utils/sign.ts diff --git a/src/common/config.ts b/src/common/config.ts index a4d73fd..b6e1f4c 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -52,6 +52,7 @@ export class ConfigUtil { autoDeleteFile: false, autoDeleteFileSecond: 60, enablePoke: false, + musicSignUrl: '', } if (!fs.existsSync(this.configPath)) { diff --git a/src/common/types.ts b/src/common/types.ts index 58fd136..82e3a32 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -28,6 +28,7 @@ export interface Config { autoDeleteFileSecond?: number ffmpeg?: string // ffmpeg路径 enablePoke?: boolean + musicSignUrl?: string } export interface LLOneBotError { diff --git a/src/common/utils/sign.ts b/src/common/utils/sign.ts new file mode 100644 index 0000000..07de2f6 --- /dev/null +++ b/src/common/utils/sign.ts @@ -0,0 +1,35 @@ +import { log } from './log' + +export interface IdMusicSignPostData { + type: 'qq' | '163' + id: string | number +} + +export interface CustomMusicSignPostData { + type: 'custom' + url: string + audio: string + title: string + image?: string + singer?: string +} + +export class MusicSign { + private readonly url: string + + constructor(url: string) { + this.url = url + } + + async sign(postData: CustomMusicSignPostData | IdMusicSignPostData): Promise { + const resp = await fetch(this.url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(postData), + }) + if (!resp.ok) throw new Error(resp.statusText) + const data = await resp.json() + log('音乐消息生成成功', data) + return data + } +} diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 8ec7f4d..7f07065 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -16,6 +16,7 @@ import { OB11MessageData, OB11MessageDataType, OB11MessageMixType, + OB11MessageMusic, OB11MessageNode, OB11PostSendMsg, } from '../../types' @@ -26,12 +27,13 @@ import { ActionName, BaseCheckResult } from '../types' import * as fs from 'node:fs' import { decodeCQCode } from '../../cqcode' import { dbUtil } from '../../../common/db' -import { ALLOW_SEND_TEMP_MSG } from '../../../common/config' +import { ALLOW_SEND_TEMP_MSG, getConfigUtil } from '../../../common/config' import { log } from '../../../common/utils/log' import { sleep } from '../../../common/utils/helper' import { uri2local } from '../../../common/utils' import { crychic } from '../../../ntqqapi/external/crychic' import { NTQQGroupApi } from '../../../ntqqapi/api' +import { MusicSign } from '../../../common/utils/sign' function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkUri(uri: string): boolean { @@ -376,16 +378,26 @@ export class SendMsg extends BaseAction { } } else { if (this.getSpecialMsgNum(payload, OB11MessageDataType.music)) { - const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic + const music = messages[0] as OB11MessageMusic if (music) { - const { url, audio, title, content, image } = music.data - const selfPeer: Peer = { peerUid: selfInfo.uid, chatType: ChatType.friend } - // 搞不定! - // const musicMsg = await this.send(selfPeer, [this.genMusicElement(url, audio, title, content, image)], [], false) - // 转发 - // const res = await NTQQApi.forwardMsg(selfPeer, peer, [musicMsg.msgId]) - // log("转发音乐消息成功", res); - // return {message_id: musicMsg.msgShortId} + const { musicSignUrl } = getConfigUtil().getConfig() + if (!musicSignUrl) { + throw '音乐签名地址未配置' + } + const { type } = music.data + if (!['qq', '163', 'custom'].includes(type)) { + throw `不支持的音乐类型 ${type}` + } + let jsonContent: string + try { + jsonContent = await new MusicSign(musicSignUrl).sign(music.data) + } catch (e) { + throw `签名音乐消息失败:${e}` + } + messages[0] = { + type: OB11MessageDataType.json, + data: { data: jsonContent }, + } } } } diff --git a/src/onebot11/types.ts b/src/onebot11/types.ts index 8b9040c..3dd281b 100644 --- a/src/onebot11/types.ts +++ b/src/onebot11/types.ts @@ -1,5 +1,6 @@ import { PicSubType, RawMessage } from '../ntqqapi/types' import { EventType } from './event/OB11BaseEvent' +import { IdMusicSignPostData, CustomMusicSignPostData } from '../common/utils/sign' export interface OB11User { user_id: number @@ -219,18 +220,18 @@ export interface OB11MessageNode { } } +export interface OB11MessageIdMusic { + type: OB11MessageDataType.music + data: IdMusicSignPostData +} + export interface OB11MessageCustomMusic { type: OB11MessageDataType.music - data: { - type: 'custom' - url: string - audio: string - title: string - content?: string - image?: string - } + data: Omit & { content?: string } } +export type OB11MessageMusic = OB11MessageIdMusic | OB11MessageCustomMusic + export interface OB11MessageJson { type: OB11MessageDataType.json data: { config: { token: string } } & any @@ -247,6 +248,7 @@ export type OB11MessageData = | OB11MessageFile | OB11MessageVideo | OB11MessageNode + | OB11MessageIdMusic | OB11MessageCustomMusic | OB11MessageJson | OB11MessagePoke diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 557d120..259941f 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -95,7 +95,9 @@ async function onSettingWindowCreated(view: Element) { HTTP 事件上报密钥
- +
@@ -158,9 +160,17 @@ async function onSettingWindowCreated(view: Element) { ), SettingItem( 'ffmpeg 路径,发送语音、视频需要,同时保证ffprobe和ffmpeg在一起', - ` 下载地址 , 路径:${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, + ` 下载地址 , 路径:${ + !isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定' + }`, SettingButton('选择ffmpeg', 'config-ffmpeg-select'), ), + SettingItem( + '音乐卡片签名地址', + null, + `
`, + 'config-musicSignUrl', + ), SettingItem('', null, SettingButton('保存', 'config-ob11-save', 'primary')), ]), SettingList([ From 1d7100a0536b603917eafc8d4d8b482d39bb4233 Mon Sep 17 00:00:00 2001 From: student_2333 Date: Tue, 30 Apr 2024 13:05:08 +0800 Subject: [PATCH 2/5] fix --- src/common/utils/sign.ts | 4 +++- src/onebot11/action/msg/SendMsg.ts | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/common/utils/sign.ts b/src/common/utils/sign.ts index 07de2f6..f289f08 100644 --- a/src/common/utils/sign.ts +++ b/src/common/utils/sign.ts @@ -14,6 +14,8 @@ export interface CustomMusicSignPostData { singer?: string } +export type MusicSignPostData = IdMusicSignPostData | CustomMusicSignPostData + export class MusicSign { private readonly url: string @@ -21,7 +23,7 @@ export class MusicSign { this.url = url } - async sign(postData: CustomMusicSignPostData | IdMusicSignPostData): Promise { + async sign(postData: MusicSignPostData): Promise { const resp = await fetch(this.url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 7f07065..829f726 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -33,7 +33,7 @@ import { sleep } from '../../../common/utils/helper' import { uri2local } from '../../../common/utils' import { crychic } from '../../../ntqqapi/external/crychic' import { NTQQGroupApi } from '../../../ntqqapi/api' -import { MusicSign } from '../../../common/utils/sign' +import { CustomMusicSignPostData, MusicSign, MusicSignPostData } from '../../../common/utils/sign' function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkUri(uri: string): boolean { @@ -304,6 +304,13 @@ export class SendMsg extends BaseAction { message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素', } } + const musicNum = this.getSpecialMsgNum(payload, OB11MessageDataType.music) + if (musicNum > 1 || fmNum != messages.length) { + return { + valid: false, + message: '音乐消息不可以和其他消息混在一起发送', + } + } if (payload.message_type !== 'private' && payload.group_id && !(await getGroup(payload.group_id))) { return { valid: false, @@ -388,9 +395,14 @@ export class SendMsg extends BaseAction { if (!['qq', '163', 'custom'].includes(type)) { throw `不支持的音乐类型 ${type}` } + const postData: MusicSignPostData = { ...music.data } + if (type === 'custom' && music.data.content) { + ;(postData as CustomMusicSignPostData).singer = music.data.content + delete (postData as OB11MessageCustomMusic['data']).content + } let jsonContent: string try { - jsonContent = await new MusicSign(musicSignUrl).sign(music.data) + jsonContent = await new MusicSign(musicSignUrl).sign(postData) } catch (e) { throw `签名音乐消息失败:${e}` } From 2abdcd23dbdb640f19990fb8738ab2f69fb2d4b8 Mon Sep 17 00:00:00 2001 From: student_2333 Date: Tue, 30 Apr 2024 13:07:51 +0800 Subject: [PATCH 3/5] fix --- src/onebot11/action/msg/SendMsg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 829f726..6423448 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -305,7 +305,7 @@ export class SendMsg extends BaseAction { } } const musicNum = this.getSpecialMsgNum(payload, OB11MessageDataType.music) - if (musicNum > 1 || fmNum != messages.length) { + if (musicNum && (musicNum > 1 || musicNum != messages.length)) { return { valid: false, message: '音乐消息不可以和其他消息混在一起发送', From 78c6050d61eea0ea47bb0370cb04566a77ec1582 Mon Sep 17 00:00:00 2001 From: student_2333 Date: Tue, 30 Apr 2024 13:08:33 +0800 Subject: [PATCH 4/5] refactor --- src/onebot11/action/msg/SendMsg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 6423448..c24929b 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -305,7 +305,7 @@ export class SendMsg extends BaseAction { } } const musicNum = this.getSpecialMsgNum(payload, OB11MessageDataType.music) - if (musicNum && (musicNum > 1 || musicNum != messages.length)) { + if (musicNum && messages.length > 1) { return { valid: false, message: '音乐消息不可以和其他消息混在一起发送', From 05091798f4c34379da05b8cb3f14b1fc2a08d353 Mon Sep 17 00:00:00 2001 From: student_2333 Date: Tue, 30 Apr 2024 13:40:15 +0800 Subject: [PATCH 5/5] fix --- src/common/utils/sign.ts | 4 +- src/ntqqapi/constructor.ts | 2 +- src/onebot11/action/msg/SendMsg.ts | 121 ++++++++++++++--------------- src/onebot11/types.ts | 2 +- 4 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/common/utils/sign.ts b/src/common/utils/sign.ts index f289f08..5fd3032 100644 --- a/src/common/utils/sign.ts +++ b/src/common/utils/sign.ts @@ -23,14 +23,14 @@ export class MusicSign { this.url = url } - async sign(postData: MusicSignPostData): Promise { + async sign(postData: MusicSignPostData): Promise { const resp = await fetch(this.url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(postData), }) if (!resp.ok) throw new Error(resp.statusText) - const data = await resp.json() + const data = await resp.text() log('音乐消息生成成功', data) return data } diff --git a/src/ntqqapi/constructor.ts b/src/ntqqapi/constructor.ts index 134b5d6..0e03dd0 100644 --- a/src/ntqqapi/constructor.ts +++ b/src/ntqqapi/constructor.ts @@ -310,7 +310,7 @@ export class SendMsgElementConstructor { } } - static ark(data: any): SendArkElement { + static ark(data: string): SendArkElement { return { elementType: ElementType.ARK, elementId: '', diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index c24929b..c516b08 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -15,6 +15,7 @@ import { OB11MessageCustomMusic, OB11MessageData, OB11MessageDataType, + OB11MessageJson, OB11MessageMixType, OB11MessageMusic, OB11MessageNode, @@ -383,34 +384,32 @@ export class SendMsg extends BaseAction { } catch (e) { throw '发送转发消息失败 ' + e.toString() } - } else { - if (this.getSpecialMsgNum(payload, OB11MessageDataType.music)) { - const music = messages[0] as OB11MessageMusic - if (music) { - const { musicSignUrl } = getConfigUtil().getConfig() - if (!musicSignUrl) { - throw '音乐签名地址未配置' - } - const { type } = music.data - if (!['qq', '163', 'custom'].includes(type)) { - throw `不支持的音乐类型 ${type}` - } - const postData: MusicSignPostData = { ...music.data } - if (type === 'custom' && music.data.content) { - ;(postData as CustomMusicSignPostData).singer = music.data.content - delete (postData as OB11MessageCustomMusic['data']).content - } - let jsonContent: string - try { - jsonContent = await new MusicSign(musicSignUrl).sign(postData) - } catch (e) { - throw `签名音乐消息失败:${e}` - } - messages[0] = { - type: OB11MessageDataType.json, - data: { data: jsonContent }, - } + } else if (this.getSpecialMsgNum(payload, OB11MessageDataType.music)) { + const music = messages[0] as OB11MessageMusic + if (music) { + const { musicSignUrl } = getConfigUtil().getConfig() + if (!musicSignUrl) { + throw '音乐签名地址未配置' } + const { type } = music.data + if (!['qq', '163', 'custom'].includes(type)) { + throw `不支持的音乐类型 ${type}` + } + const postData: MusicSignPostData = { ...music.data } + if (type === 'custom' && music.data.content) { + ;(postData as CustomMusicSignPostData).singer = music.data.content + delete (postData as OB11MessageCustomMusic['data']).content + } + let jsonContent: string + try { + jsonContent = await new MusicSign(musicSignUrl).sign(postData) + } catch (e) { + throw `签名音乐消息失败:${e}` + } + messages[0] = { + type: OB11MessageDataType.json, + data: { data: jsonContent }, + } as OB11MessageJson } } // log("send msg:", peer, sendElements) @@ -579,41 +578,41 @@ export class SendMsg extends BaseAction { } } - private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement { - const musicJson = { - app: 'com.tencent.structmsg', - config: { - ctime: 1709689928, - forward: 1, - token: '5c1e4905f926dd3a64a4bd3841460351', - type: 'normal', - }, - extra: { app_type: 1, appid: 100497308, uin: selfInfo.uin }, - meta: { - news: { - action: '', - android_pkg_name: '', - app_type: 1, - appid: 100497308, - ctime: 1709689928, - desc: content || title, - jumpUrl: url, - musicUrl: audio, - preview: image, - source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0', - source_url: '', - tag: 'QQ音乐', - title: title, - uin: selfInfo.uin, - }, - }, - prompt: content || title, - ver: '0.0.0.1', - view: 'news', - } + // private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement { + // const musicJson = { + // app: 'com.tencent.structmsg', + // config: { + // ctime: 1709689928, + // forward: 1, + // token: '5c1e4905f926dd3a64a4bd3841460351', + // type: 'normal', + // }, + // extra: { app_type: 1, appid: 100497308, uin: selfInfo.uin }, + // meta: { + // news: { + // action: '', + // android_pkg_name: '', + // app_type: 1, + // appid: 100497308, + // ctime: 1709689928, + // desc: content || title, + // jumpUrl: url, + // musicUrl: audio, + // preview: image, + // source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0', + // source_url: '', + // tag: 'QQ音乐', + // title: title, + // uin: selfInfo.uin, + // }, + // }, + // prompt: content || title, + // ver: '0.0.0.1', + // view: 'news', + // } - return SendMsgElementConstructor.ark(musicJson) - } + // return SendMsgElementConstructor.ark(musicJson) + // } } export default SendMsg diff --git a/src/onebot11/types.ts b/src/onebot11/types.ts index 3dd281b..c3393a9 100644 --- a/src/onebot11/types.ts +++ b/src/onebot11/types.ts @@ -234,7 +234,7 @@ export type OB11MessageMusic = OB11MessageIdMusic | OB11MessageCustomMusic export interface OB11MessageJson { type: OB11MessageDataType.json - data: { config: { token: string } } & any + data: { data: string /* , config: { token: string } */ } } export type OB11MessageData =