mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1ecd5b78e6 | ||
![]() |
fca2e3c51a | ||
![]() |
95ea761b2d | ||
![]() |
6b3bfa1ee9 | ||
![]() |
df3e302a9d | ||
![]() |
c88a68c9a8 | ||
![]() |
92d01b9cdd |
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.5.21",
|
||||
"version": "4.5.22",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -1,19 +1,21 @@
|
||||
import { PlayMode } from '@/const/enum'
|
||||
|
||||
import WebUIManager from '@/controllers/webui_manager'
|
||||
import type {
|
||||
FinalMusic,
|
||||
Music163ListResponse,
|
||||
Music163URLResponse
|
||||
} from '@/types/music'
|
||||
|
||||
import WebUIManager from '@/controllers/webui_manager'
|
||||
/**
|
||||
* 获取网易云音乐歌单
|
||||
* @param id 歌单id
|
||||
* @returns 歌单信息
|
||||
*/
|
||||
export const get163MusicList = async (id: string) => {
|
||||
let res = await WebUIManager.proxy<Music163ListResponse>('https://wavesgame.top/playlist/track/all?id=' + id);
|
||||
let res = await WebUIManager.proxy<Music163ListResponse>(
|
||||
'https://wavesgame.top/playlist/track/all?id=' + id
|
||||
)
|
||||
// const res = await request.get<Music163ListResponse>(
|
||||
// `https://wavesgame.top/playlist/track/all?id=${id}`
|
||||
// )
|
||||
@@ -71,7 +73,7 @@ export const get163MusicListSongs = async (id: string) => {
|
||||
if (songURL) {
|
||||
finalMusic.push({
|
||||
id: song.id,
|
||||
url: songURL,
|
||||
url: songURL.replace(/http:\/\//, '//').replace(/https:\/\//, '//'),
|
||||
title: song.name,
|
||||
artist: song.ar.map((p) => p.name).join('/'),
|
||||
cover: song.al.picUrl
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.5.21",
|
||||
"version": "4.5.22",
|
||||
"scripts": {
|
||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '4.5.21';
|
||||
export const napCatVersion = '4.5.22';
|
||||
|
2
src/core/external/offset.json
vendored
2
src/core/external/offset.json
vendored
@@ -175,7 +175,7 @@
|
||||
"send": "713A318",
|
||||
"recv": "713DB50"
|
||||
},
|
||||
"6.9.63.30851-x64": {
|
||||
"6.9.63-30851-x64": {
|
||||
"send": "46C8040",
|
||||
"recv": "46CA8AC"
|
||||
},
|
||||
|
@@ -1,22 +1,22 @@
|
||||
import * as crypto from 'crypto';
|
||||
import {PacketContext} from '@/core/packet/context/packetContext';
|
||||
import { PacketContext } from '@/core/packet/context/packetContext';
|
||||
import * as trans from '@/core/packet/transformer';
|
||||
import {PacketMsg} from '@/core/packet/message/message';
|
||||
import { PacketMsg } from '@/core/packet/message/message';
|
||||
import {
|
||||
PacketMsgFileElement,
|
||||
PacketMsgPicElement,
|
||||
PacketMsgPttElement,
|
||||
PacketMsgVideoElement
|
||||
} from '@/core/packet/message/element';
|
||||
import {ChatType, MsgSourceType, NTMsgType, RawMessage} from '@/core';
|
||||
import {MiniAppRawData, MiniAppReqParams} from '@/core/packet/entities/miniApp';
|
||||
import {AIVoiceChatType} from '@/core/packet/entities/aiChat';
|
||||
import {NapProtoDecodeStructType, NapProtoEncodeStructType, NapProtoMsg} from '@napneko/nap-proto-core';
|
||||
import {IndexNode, LongMsgResult, MsgInfo} from '@/core/packet/transformer/proto';
|
||||
import {OidbPacket} from '@/core/packet/transformer/base';
|
||||
import {ImageOcrResult} from '@/core/packet/entities/ocrResult';
|
||||
import {gunzipSync} from 'zlib';
|
||||
import {PacketMsgConverter} from '@/core/packet/message/converter';
|
||||
import { ChatType, MsgSourceType, NTMsgType, RawMessage } from '@/core';
|
||||
import { MiniAppRawData, MiniAppReqParams } from '@/core/packet/entities/miniApp';
|
||||
import { AIVoiceChatType } from '@/core/packet/entities/aiChat';
|
||||
import { NapProtoDecodeStructType, NapProtoEncodeStructType, NapProtoMsg } from '@napneko/nap-proto-core';
|
||||
import { IndexNode, LongMsgResult, MsgInfo } from '@/core/packet/transformer/proto';
|
||||
import { OidbPacket } from '@/core/packet/transformer/base';
|
||||
import { ImageOcrResult } from '@/core/packet/entities/ocrResult';
|
||||
import { gunzipSync } from 'zlib';
|
||||
import { PacketMsgConverter } from '@/core/packet/message/converter';
|
||||
|
||||
export class PacketOperationContext {
|
||||
private readonly context: PacketContext;
|
||||
@@ -59,10 +59,10 @@ export class PacketOperationContext {
|
||||
const res = trans.GetStrangerInfo.parse(resp);
|
||||
const extBigInt = BigInt(res.data.status.value);
|
||||
if (extBigInt <= 10n) {
|
||||
return {status: Number(extBigInt) * 10, ext_status: 0};
|
||||
return { status: Number(extBigInt) * 10, ext_status: 0 };
|
||||
}
|
||||
status = Number((extBigInt & 0xff00n) + ((extBigInt >> 16n) & 0xffn));
|
||||
return {status: 10, ext_status: status};
|
||||
return { status: 10, ext_status: status };
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
@@ -79,13 +79,13 @@ export class PacketOperationContext {
|
||||
const reqList = msg.flatMap(m =>
|
||||
m.msg.map(e => {
|
||||
if (e instanceof PacketMsgPicElement) {
|
||||
return this.context.highway.uploadImage({chatType, peerUid}, e);
|
||||
return this.context.highway.uploadImage({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgVideoElement) {
|
||||
return this.context.highway.uploadVideo({chatType, peerUid}, e);
|
||||
return this.context.highway.uploadVideo({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgPttElement) {
|
||||
return this.context.highway.uploadPtt({chatType, peerUid}, e);
|
||||
return this.context.highway.uploadPtt({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgFileElement) {
|
||||
return this.context.highway.uploadFile({chatType, peerUid}, e);
|
||||
return this.context.highway.uploadFile({ chatType, peerUid }, e);
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean)
|
||||
@@ -160,6 +160,12 @@ export class PacketOperationContext {
|
||||
const res = trans.DownloadGroupFile.parse(resp);
|
||||
return `https://${res.download.downloadDns}/ftn_handler/${Buffer.from(res.download.downloadUrl).toString('hex')}/?fname=`;
|
||||
}
|
||||
async GetPrivateFileUrl(self_id: string, fileUUID: string, md5: string) {
|
||||
const req = trans.DownloadPrivateFile.build(self_id, fileUUID, md5);
|
||||
const resp = await this.context.client.sendOidbPacket(req, true);
|
||||
const res = trans.DownloadPrivateFile.parse(resp);
|
||||
return `http://${res.body?.result?.server}:${res.body?.result?.port}${res.body?.result?.url?.slice(8)}&isthumb=0`;
|
||||
}
|
||||
|
||||
async GetGroupPttUrl(groupUin: number, node: NapProtoEncodeStructType<typeof IndexNode>) {
|
||||
const req = trans.DownloadGroupPtt.build(groupUin, node);
|
||||
|
@@ -465,14 +465,14 @@ export interface NodeIKernelMsgService {
|
||||
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
||||
|
||||
clickInlineKeyboardButton(params: {
|
||||
guildId: string,
|
||||
guildId?: string,
|
||||
peerId: string,
|
||||
botAppid: string,
|
||||
msgSeq: string,
|
||||
buttonId: string,
|
||||
callback_data: string,
|
||||
dmFlag: number,
|
||||
chatType: number
|
||||
chatType: number // 1私聊 2群
|
||||
}): Promise<GeneralCallResult & { status: number, promptText: string, promptType: number, promptIcon: number }>;
|
||||
|
||||
setCurOnScreenMsg(...args: unknown[]): unknown;
|
||||
|
@@ -7,6 +7,7 @@ const SchemaData = Type.Object({
|
||||
bot_appid: Type.String(),
|
||||
button_id: Type.String({ default: '' }),
|
||||
callback_data: Type.String({ default: '' }),
|
||||
msg_seq: Type.String({ default: '10086' }),
|
||||
});
|
||||
|
||||
type Payload = Static<typeof SchemaData>;
|
||||
@@ -18,13 +19,12 @@ export class ClickInlineKeyboardButton extends OneBotAction<Payload, unknown> {
|
||||
async _handle(payload: Payload) {
|
||||
return await this.core.apis.MsgApi.clickInlineKeyboardButton({
|
||||
buttonId: payload.button_id,
|
||||
guildId: '',// 频道使用
|
||||
peerId: payload.group_id.toString(),
|
||||
botAppid: payload.bot_appid,
|
||||
msgSeq: '10086',
|
||||
msgSeq: payload.msg_seq,
|
||||
callback_data: payload.callback_data,
|
||||
dmFlag: 0,
|
||||
chatType: 1
|
||||
chatType: 2
|
||||
})
|
||||
}
|
||||
}
|
||||
|
36
src/onebot/action/file/GetPrivateFileUrl.ts
Normal file
36
src/onebot/action/file/GetPrivateFileUrl.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { FileNapCatOneBotUUID } from '@/common/file-uuid';
|
||||
import { GetPacketStatusDepends } from '@/onebot/action/packet/GetPacketStatus';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const SchemaData = Type.Object({
|
||||
file_id: Type.String(),
|
||||
});
|
||||
|
||||
type Payload = Static<typeof SchemaData>;
|
||||
|
||||
interface GetPrivateFileUrlResponse {
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export class GetPrivateFileUrl extends GetPacketStatusDepends<Payload, GetPrivateFileUrlResponse> {
|
||||
override actionName = ActionName.NapCat_GetPrivateFileUrl;
|
||||
override payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id);
|
||||
|
||||
if (contextMsgFile?.fileUUID && contextMsgFile.msgId) {
|
||||
let msg = await this.core.apis.MsgApi.getMsgsByMsgId(contextMsgFile.peer, [contextMsgFile.msgId]);
|
||||
let self_id = this.core.selfInfo.uid;
|
||||
let file_hash = msg.msgList[0]?.elements.map(ele => ele.fileElement?.file10MMd5)[0];
|
||||
if (file_hash) {
|
||||
return {
|
||||
url: await this.core.apis.PacketApi.pkt.operation.GetPrivateFileUrl(self_id, contextMsgFile.fileUUID, file_hash)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
throw new Error('real fileUUID not found!');
|
||||
}
|
||||
}
|
@@ -106,6 +106,7 @@ import { SendPoke } from '@/onebot/action/packet/SendPoke';
|
||||
import { SetDiyOnlineStatus } from './extends/SetDiyOnlineStatus';
|
||||
import { BotExit } from './extends/BotExit';
|
||||
import { ClickInlineKeyboardButton } from './extends/ClickInlineKeyboardButton';
|
||||
import { GetPrivateFileUrl } from './file/GetPrivateFileUrl';
|
||||
|
||||
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
|
||||
|
||||
@@ -225,6 +226,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
||||
new GetGroupSystemMsg(obContext, core),
|
||||
new BotExit(obContext, core),
|
||||
new ClickInlineKeyboardButton(obContext, core),
|
||||
new GetPrivateFileUrl(obContext,core)
|
||||
];
|
||||
|
||||
type HandlerUnion = typeof actionHandlers[number];
|
||||
|
@@ -10,6 +10,7 @@ export interface InvalidCheckResult {
|
||||
}
|
||||
|
||||
export const ActionName = {
|
||||
NapCat_GetPrivateFileUrl: 'get_private_file_url',
|
||||
ClickInlineKeyboardButton: 'click_inline_keyboard_button',
|
||||
GetUnidirectionalFriendList: 'get_unidirectional_friend_list',
|
||||
// onebot 11
|
||||
|
@@ -132,7 +132,6 @@ export class OneBotMsgApi {
|
||||
file: element.fileName,
|
||||
sub_type: element.picSubType,
|
||||
url: await this.core.apis.FileApi.getImageUrl(element),
|
||||
path: element.filePath,
|
||||
file_size: element.fileSize,
|
||||
},
|
||||
};
|
||||
@@ -148,13 +147,13 @@ export class OneBotMsgApi {
|
||||
peerUid: msg.peerUid,
|
||||
guildId: '',
|
||||
};
|
||||
const file = FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, element.fileName);
|
||||
FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, element.fileUuid);
|
||||
FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, element.fileName);
|
||||
return {
|
||||
type: OB11MessageDataType.file,
|
||||
data: {
|
||||
file: file,
|
||||
path: element.filePath,
|
||||
file_id: file,
|
||||
file: element.fileName,
|
||||
file_id: element.fileUuid,
|
||||
file_size: element.fileSize,
|
||||
},
|
||||
};
|
||||
@@ -216,7 +215,6 @@ export class OneBotMsgApi {
|
||||
data: {
|
||||
summary: _.faceName, // 商城表情名称
|
||||
file: filename,
|
||||
path: url,
|
||||
url: url,
|
||||
key: _.key,
|
||||
emoji_id: _.emojiId,
|
||||
@@ -339,7 +337,6 @@ export class OneBotMsgApi {
|
||||
type: OB11MessageDataType.video,
|
||||
data: {
|
||||
file: fileCode,
|
||||
path: videoDownUrl,
|
||||
url: videoDownUrl,
|
||||
file_size: element.fileSize,
|
||||
},
|
||||
@@ -357,7 +354,6 @@ export class OneBotMsgApi {
|
||||
type: OB11MessageDataType.voice,
|
||||
data: {
|
||||
file: fileCode,
|
||||
path: element.filePath,
|
||||
file_size: element.fileSize,
|
||||
},
|
||||
};
|
||||
|
Reference in New Issue
Block a user