Skip to content

API 使用文档 (TypeScript JavaScript)

padlocal edited this page Apr 23, 2023 · 14 revisions

BOT

创建BOT

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,
  });
}

启动并登录BOT

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;
}

主动登出BOT

await bot.logout();

Message

/**
 * 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);

发送视频

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;
    }
  });

Contact

获取所有联系人列表

// 所有联系人列表中,包含了聊天室中哪些不认识联系人
const allContactList = await bot.Contact.findAll();

// 获取你添加过的好友。和微信一样,不知道对方是否删除了你
const friendList = allContactList.filter(contact => contact.friend());

判断联系人是否为好友

const isFriend: boolean = contact.friend();

获取/设置BOT自己的昵称

const self = bot.userSelf();

// 获取
const oldName = self.name();

// 设置
const toName: string = "NEW NICK NAME"
await self.name(toName);

获取BOT自己的二维码

const self = bot.userSelf();
const qrStr = await self.qrcode();
// 再用二维码生成工具将 qrStr 生成为二维码即可

设置BOT自己的签名

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!, "朋友,你好");

Room

获取群聊列表

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}`);
});

Tag

为用户添加标签

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 官方文档

Clone this wiki locally