generated from wechaty/puppet-mock
-
Notifications
You must be signed in to change notification settings - Fork 88
API 使用文档 (TypeScript JavaScript)
padlocal edited this page Apr 23, 2023
·
14 revisions
import { PuppetPadlocal } from "wechaty-puppet-padlocal";
export function createBot(): Wechaty {
const token: string = "YOUR_PADLOCAL_TOKEN";
const puppet = new PuppetPadlocal({
token,
});
return new Wechaty({
name: "BotName",
puppet,
});
}
import QRCode from "qrcode-terminal";
export async function prepareBot(): Promise<Wechaty> {
const bot = createBot();
// 在这里监听感兴趣的 bot 事件回调。
bot.on("scan", (qrcode: string, status: ScanStatus) => {
if (status === ScanStatus.Waiting && qrcode) {
log.info(
"TestBot",
`onScan: ${ScanStatus[status]}(${status})\n\n ▼▼▼ Please scan following qr code to login ▼▼▼\n`
);
QRCode.generate(qrcode, { small: true });
} else {
log.info("TestBot", `onScan: ${ScanStatus[status]}(${status})`);
}
})
.on("login", (user: Contact) => {
// login 事件并不代表登录完全完成,只是通知目前登录的账号是什么,后续仍有初始化任务需要完成。
log.info("TestBot", "%s login", user);
})
.on("logout", (user: Contact, reason: string) => {
log.info("TestBot", "%s logout, reason:%s", user, reason);
});
await bot.start();
await bot.ready();
// !!!只有当 bot ready 才能保证 bot 已经完全登录且初始化成功,这之后才能调用 bot 各种API
return bot;
}
- 完全事件列表参考:
WechatyEventName
。以及每个事件对应的回调数据类型:WechatyEventFunction
await bot.logout();
/**
* toUserId: wxid_xxx | xxx@chatroom
* payload: string | number | Message | Contact | FileBox | MiniProgram | UrlLink
*/)
const sendMessage = async (toUserId: string, payload: any): Promise<Message> => {
const toContact = await bot.Contact.load(toUserId);
const message = (await toContact.say(payload)) as Message;
return message;
};
const message = await sendMessage("TO", "Hello World");
const toRoom = await bot.Room.load("xxx@chatroom");
const atUserIdList = ["wxid_xxx", "wxid_yyy"];
const atUserList: Contact[] = [];
for (const userId of atUserIdList) {
const contact = await bot.Contact.load(userId);
atUserList.push(contact!);
}
const message = (await toRoom.say(payload, ...atUserList)) as Message;
const contactCard = (await bot.Contact.find({ id: "wxid_" }))!;
await await sendMessage("TO", contactCard);
// 图片大小建议不要超过 2 M
const imageFilePath = "/Users/.../image.jpeg";
const fileBox = FileBox.fromFile(imageFilePath);
// const fileBox = FileBox.fromUrl("https://.../image.jpeg");
const message = await sendMessage("TO", fileBox);
// 语音文件为 silk 格式。silk 是 skype 开源的一款语音编解码器,被微信的语音文件所采用。
// 注意:文件后缀必须是 `sil`!
const voiceFilePath = "/Users/.../voice.sil"
const voiceLength = 6000; // 需要提供语音长度,单位为毫秒
const fileBox = FileBox.fromFile(voiceFilePath);
fileBox.mimeType = "audio/silk";
fileBox.metadata = {
voiceLength,
};
const message = await sendMessage("TO", fileBox);
- silk 转码工具:
silk-v3-decoder
const videoFilePath = "/Users/.../video.mp4";
const fileBox = FileBox.fromFile(videoFilePath);
// const fileBox = FileBox.fromUrl("https://.../video.mp4");
const message = await sendMessage("TO", fileBox);
const fileFilePath = "/Users/.../文件.pdf";
const fileBox = FileBox.fromFile(fileFilePath);
// const fileBox = FileBox.fromUrl("https://.../文件.pdf");
const message = await sendMessage("TO", fileBox);
const urlLink = new UrlLink({
title: "Hello World! 你好世界!",
description: "This is description。描述可中文",
thumbnailUrl: "https://.../thumb.jpg",
url: "https://...",
});
const message = await sendMessage("TO", urlLink);
// 封面图片为 cdn 图片
const miniProgramPayload: MiniProgramPayload = {
appid: "wx363a...",
description: "贝壳找房 - 真房源",
title: "美国白宫,10室8厅9卫,99999刀/月",
iconUrl: "http://mmbiz.qpic.cn/mmbiz_png/.../640?wx_fmt=png&wxfrom=200",
pagePath: "pages/home/home.html...",
shareId: "0_wx363afd5a1384b770_..._1615104758_0",
thumbKey: "84db921169862291...",
thumbUrl: "3051020100044a304802010002046296f57502033d14...",
username: "gh_8a51...@app"
}
// 封面图片为自定义外部图片(注意控制图片大小)
const miniProgramPayload: MiniProgramPayload = {
appid: "wx363a...",
description: "贝壳找房 - 真房源",
title: "美国白宫,10室8厅9卫,99999刀/月",
iconUrl: "http://mmbiz.qpic.cn/mmbiz_png/.../640?wx_fmt=png&wxfrom=200",
pagePath: "pages/home/home.html...",
shareId: "0_wx363afd5a1384b770_..._1615104758_0",
thumbKey: undefined,
thumbUrl: "https://.../thumb.jpeg", // 推荐在 200K 以内,比例 5:4,宽度不大于 1080px
username: "gh_8a51...@app",
};
const miniProgram = new MiniProgram(miniProgramPayload);
const message = await sendMessage("TO", miniProgram);
这些参数就是收到的表情消息中的数据。
const emoticonBox = FileBox.fromUrl("http://emoji.qpic.cn/wx_emoji/.../", `message-emotion.jpg`);
emoticonBox.mimeType = "emoticon";
emoticonBox.metadata = {
md5: "45229f68c17167f57ba9393004fcef98",
len: 12345,
type: 2,
gameext: "",
};
const message = await sendMessage("TO", emoticonBox);
await message.recall()
bot.on("message", async (message: Message) => {
switch (message.type()) {
// 文本消息
case MessageType.Text:
const text = message.text();
break;
// 图片消息
case MessageType.Image:
const messageImage = await message.toImage();
// 缩略图
const thumbImage = await messageImage.thumbnail();
const thumbImageData = await thumbImage.toBuffer();
// thumbImageData: 缩略图图片二进制数据
// 大图
const hdImage = await messageImage.hd();
const hdImageData = await hdImage.toBuffer();
// 大图图片二进制数据
// 原图
const artworkImage = await messageImage.artwork();
const artworkImageData = await artworkImage.toBuffer();
// artworkImageData: 原图图片二进制数据
break;
// 链接卡片消息
case MessageType.Url:
const urlLink: UrlLink = await message.toUrlLink();
// urlLink: 链接主要数据:包括 title,URL,description
const urlThumbImage = await message.toFileBox();
const urlThumbImageData = await urlThumbImage.toBuffer();
// urlThumbImageData: 链接的缩略图二进制数据
break;
// 小程序卡片消息
case MessageType.MiniProgram:
const miniProgram: MiniProgram = await message.toMiniProgram();
/*
miniProgram: 小程序卡片数据
{
appid: "wx363a...",
description: "贝壳找房 - 真房源",
title: "美国白宫,10室8厅9卫,99999刀/月",
iconUrl: "http://mmbiz.qpic.cn/mmbiz_png/.../640?wx_fmt=png&wxfrom=200",
pagePath: "pages/home/home.html...",
shareId: "0_wx363afd5a1384b770_..._1615104758_0",
thumbKey: "84db921169862291...",
thumbUrl: "3051020100044a304802010002046296f57502033d14...",
username: "gh_8a51...@app"
}
*/
break;
// 语音消息
case MessageType.Audio:
const audioFileBox = await message.toFileBox();
const audioData: Buffer = await audioFileBox.toBuffer();
// audioData: silk 格式的语音文件二进制数据
break;
// 视频消息
case MessageType.Video:
const videoFileBox = await message.toFileBox();
const videoData: Buffer = await videoFileBox.toBuffer();
// videoData: 视频文件二进制数
break;
// 动图表情消息
case MessageType.Emoticon:
const emotionFile = await message.toFileBox();
const emotionData: Buffer = await emotionFile.toBuffer();
// emotionData: 动图 Gif文件 二进制数据
break;
// 文件消息
case MessageType.Attachment:
const attachFileBox = await message.toFileBox();
const attachData = await attachFileBox.toBuffer();
// attachData: 文件二进制数据
break;
// 其他消息
default:
break;
}
});
- silk 转码工具:
silk-v3-decoder
// 所有联系人列表中,包含了聊天室中哪些不认识联系人
const allContactList = await bot.Contact.findAll();
// 获取你添加过的好友。和微信一样,不知道对方是否删除了你
const friendList = allContactList.filter(contact => contact.friend());
const isFriend: boolean = contact.friend();
const self = bot.userSelf();
// 获取
const oldName = self.name();
// 设置
const toName: string = "NEW NICK NAME"
await self.name(toName);
const self = bot.userSelf();
const qrStr = await self.qrcode();
// 再用二维码生成工具将 qrStr 生成为二维码即可
const self = bot.userSelf();
await self.signature("NEW SIGNATURE");
const contact = (await bot.Contact.find({ id: "wxid_xxx" }))!;
// 获取
const oldAlias = await contact.alias();
// 设置
await contact.alias("新的备注");
// 自己
const selfContact = bot.userSelf();
const selfAvatarFileBox: FileBox = await selfContact.avatar();
// 他人
const contact = (await bot.Contact.find({ id:"wxid_xxx" }))!;
const otherAvatarFileBox: FileBox = await contact.avatar();
const puppet: PuppetPadlocal = bot.puppet as PuppetPadlocal;
await puppet.contactDelete(deleteUserName);
// contact 对象仍然可以得到,但是 friend 变为了 false
const contact = await bot.Contact.find({ id: deleteUserName });
expect(contact!.friend()).toBeFalsy();
bot.on("friendship", async (friendship: Friendship) => {
if (friendship.type() === FriendshipType.Receive) {
await friendship.accept();
}
});
// 这种方式的前提是:必须已经知道了对方的 id
const contact = await bot.Contact.find({ id: "wxid_" });
await bot.Friendship.add(contact!, hello);
const contact = await bot.Friendship.search({ phone: "135xxx" });
await bot.Friendship.add(contact!, "朋友,你好");
const contact = await bot.Friendship.search({ weixin: "PadLocal" });
await bot.Friendship.add(contact!, "朋友,你好");
const allRooms = await bot.Room.findAll();
// 至少两个其他好友
const memberIdList = ["wxid_xxx", "wxid_yyy"];
const contactList = [];
for (const userId of memberIdList) {
const contact = await bot.Contact.find({ id: userId });
contactList.push(contact!);
}
const roomName = "PadLocal";
const newRoom = await bot.Room.create(contactList, roomName);
await newRoom.ready();
await newRoom.say("Hello World!");
const memberList = await room.memberAll();
const room = (await bot.Room.find({ id: "xxx@chatroom" }))!;
const contact = await bot.Contact.find({ id: "wxid_" });
await room!.add(contact!);
// 稍微等待一下
await new Promise((resolve) => setTimeout(resolve, 1000));
// newMemberList 就包含新添加的成员了
const newMemberList = await room.memberAll();
const room = (await bot.Room.find({ id: "xxx@chatroom" }))!;
const contact = await bot.Contact.find({ id: "wxid_" });
await room.del(contact!);
// 稍微等待一下
await new Promise((resolve) => setTimeout(resolve, 1000));
// newMemberList 就不包含被删除的联系人
const newMemberList = await room.memberAll();
const avatarFileBox = await room!.avatar();
二维码需要 bot 保持在线至少24小时后才能获取,否则会出现“生成的群二维码已经失效”的错误
const qrString = await room.qrCode();
// 用二维码生成工具,将 qrString 生成为二维码即可
// 获取
const oldTopic = await room.topic();
// 设置
await room.topic("新的群聊名称");
// 获取
const announcement = await room.announce();
// 设置
await room.announce("新的群公告");
await room.quit();
bot.on("room-invite", async (roomInvite: RoomInvitation) => {
await roomInvite.accept();
});
bot.on("room-join", async (room: Room, inviteeList: Contact[], inviter: Contact, date) => {
log.info(
`on room join: ${room.toString()}, inviteeList: ${inviteeList.map((i) => i.id)}, inviter: ${
inviter.id
}, ${date}`
);
});
只有自己是群主或管理员的群才能收到退出群聊通知。
bot.on("room-leave", async (room: Room, leaverList: Contact[], remover?: Contact, date?: Date) => {
log.info(
`on room leave: ${room.toString()}, leaverList: ${leaverList.map((l) => l.id)}, remover: ${
remover?.id
} ${date}`
);
});
bot.on("room-topic", async (room: Room, newTopic: string, oldTopic: string, changer: Contact, date?: Date) => {
log.info(`on room topic: ${room.toString()}, ${newTopic}, ${oldTopic}, ${changer.toString()}, ${date}`);
});
const tag = await bot.Tag.get("标签名称");
const contact = await bot.Contact.find({ id: "wxid_xxx" });
await tag.add(contact!);
const tag = await bot.Tag.get("标签名称");
const contact = await bot.Contact.find({ id: "wxid_xxx" });
await tag.remove(contact!);
const tag = await bot.Tag.get("标签名称");
await bot.Tag.delete(tag);
const contact = await bot.Contact.find({ id: "wxid_xxx" });
const tags = await contact!.tags();
本文档主要针对 PadLocal 给出使用示例,更丰富的文档请查阅:Wechaty 官方文档
Don't be evil
GETTING STARTED
- How to Apply Token
- Getting Started with TypeScript/JavaScript(RECOMMENDED)
- Getting Started with Python/Java/Go
REFERENCE
ADVANCED GUIDES