khl.py khl.py
主页
文档
示例
  • khl.py (opens new window)
  • khl.py.docs (opens new window)
KOOK (opens new window)
主页
文档
示例
  • khl.py (opens new window)
  • khl.py.docs (opens new window)
KOOK (opens new window)
  • 机器人

    • 初始化
    • 命令
    • 定时任务
    • 在玩状态
  • 消息

    • 消息类型
    • 上传和发送文件或图片
    • 卡片消息
      • 1.说明
      • 2.文字
      • 3.分行符
      • 4.卡片边栏颜色
      • 5.多列文字
      • 6.图片
        • 6.1 单图
        • 6.2 图片+文字
        • 6.3 多图
      • 7.按钮
        • 7.1 参数说明
        • 7.2 多按钮示例
        • 7.3 按钮点击事件
        • 7.4 按钮+文字
      • 8.倒计时
  • 频道

    • 获取频道对象
    • 主动发送消息
  • 用户

    • 获取机器人用户对象
    • 获取用户对象和发送私聊信息
    • 机器人下线
  • 服务器

    • 获取服务器对象
    • 服务器角色操作
    • 设置用户昵称
  • 事件

    • 事件基础处理
  • 其他

    • KOOK客户端获取各类ID
    • 多文件注册机器人命令
    • 配置python的venv虚拟环境
    • 获取图片链接
    • 尝试自己调用api
  • docs
  • 消息
musnows
2023-09-05
目录
1.说明
2.文字
3.分行符
4.卡片边栏颜色
5.多列文字
6.图片
6.1 单图
6.2 图片+文字
6.3 多图
7.按钮
7.1 参数说明
7.2 多按钮示例
7.3 按钮点击事件
7.4 按钮+文字
8.倒计时

卡片消息

本页面测试代码可见 code/05.msg.py (opens new window)

# 1.说明

卡片消息的不同格式有很多,基本集中于Card和CardMessage类型中,需要从 khl.card 中导入;

from khl.card import Card, CardMessage, Module, Types, Element, Struct

消息发送 msg.reply() 函数只接受 CardMessage 对象,一个CardMessage对象最多包含5个Card(超出会无法发送);

c = Card() # 在这里补充卡片消息的内容(空卡片消息无法发送)
await msg.reply(CardMessage(c))

Card和CardMessage本质上是封装了一层Json字符串,CardMessage类型是一个list,你可以使用json模组将其还原成字符串;

cm = CardMessage() # 假设这是一个完好的卡片消息
print(json.dumps(cm)) # 将卡片消息转换成json字符串

在卡片消息发送失败的时候,你可以将CardMessage对象转成Json字符串,并去到官方的卡片编辑器 (opens new window)中,粘贴Json,查看卡片编辑器底部显示的错误信息。

卡片消息发送失败会触发如下异常:

khl.requester.HTTPRequester.APIRequestFailed: Requesting 'POST message/create' failed with 40000: 卡片消息json没有通过验证或者不存在

# 2.文字

除了标题外,正文和小字都支持KMD,在新版本的khl.py中,已经默认了卡片消息的文字类型为KMD

cm = CardMessage()
c = Card(
    Module.Header("标题内容,不支持`KMD`"),
    Module.Context("小字,支持`KMD`"),
    Module.Section("正文内容,支持`KMD`"),
)

cm.append(c)
# 你可以继续往cm中append其他Card对象,最多5个
# cm.append(c1)
await msg.reply(cm)

image-20230906085459881

如果你使用的是旧版本的khl.py,则可以使用这种方式来指定文字类型为KMD;同时这里也演示了你可以使用append将Moudle给插入到Card中,效果和上图完全相同;

# 手动指定使用kmd
c1 = Card(
    Module.Header("标题内容,不支持`KMD`")
)
c1.append(Module.Context(Element.Text("小字,支持`KMD`",Types.Text.KMD)))
c1.append(Module.Section(Element.Text("正文内容,支持`KMD`",Types.Text.KMD)))

彩色文字的用法请参考官方卡片编辑器中KMD的语法:

(font)安全免费(font)[success] (font)没有广告(font)[purple] (font)低资源占用(font)[warning] (font)高通话质量(font)[pink]

image-20230906145901209

# 3.分行符

c1 = Card()
c1.append(Module.Divider()) # 分隔符

下图小字和正文之间的横线就是分隔符

image-20230906090220804

# 4.卡片边栏颜色

在构造Card类型的时候,可以传入color参数来指定卡片消息边栏的颜色,默认是蓝色

c1 = Card(
    Module.Header("标题内容,不支持`KMD`"),
    color='#1f1f1f'
)

你可以根据你的需要,传入颜色的十六进制值;可以在在线网站 (opens new window)中查询颜色对应值,搜索关键字“RGB颜色十六进制码”。

image-20230906090552051

# 5.多列文字

卡片消息支持多列文字,最多3列;在每一列的字符串中换行,既可以实现一列多行。

你可以将第一列加粗来作为“表头”,具体请根据你的需求自行决定样式。

c2 = Card(
    Module.Section(
        Struct.Paragraph(
            3,
            Element.Text("这是第一列", type=Types.Text.KMD),
            Element.Text("这是第二列", type=Types.Text.KMD),
            Element.Text("这是第三列", type=Types.Text.KMD),
        )
    )
)

image-20230906091959642

# 6.图片

在卡片消息中,你可以将图片设置成任意国内可访问的图片外链链接,也可以先使用create_asssets函数将图片上传到kook的图床,获取到链接后,再写入卡片消息中。

请注意,如果你的图片外链国内无法访问或者访问不稳定,则卡片消息会发送失败。强烈建议将图片先上传到kook图床再发送,具体步骤请参考 图片上传 一节;

# 6.1 单图

img_src = "https://img.kookapp.cn/attachments/2023-05/29/k2jUQW81GC05k05k.png"
c3 = Card(Module.Container(Element.Image(src=img_src)))

image-20230529105207644

# 6.2 图片+文字

这里的图片我直接传入了发起命令的用户头像,默认情况下,图片会显示在文字的左侧

c4 = Card(
    Module.Section(
        Element.Text("文字在右侧", type=Types.Text.KMD),
        Element.Image(src=msg.author.avatar),
    )
)

image-20230906094852032

你可以传入mode,让图片显示在文字的右侧

c5 = Card(
    Module.Section(
        Element.Text("文字在左侧", type=Types.Text.KMD),
        Element.Image(src=msg.author.avatar),
        mode=Types.SectionMode.RIGHT
    )
)

image-20230906145038029

给Element.Image传入sz参数,设置图片的大小,圆角

c6 = Card(
    Module.Section(
        Element.Text("文字在左侧", type=Types.Text.KMD),
        Element.Image(src=msg.author.avatar,size=Types.Size.SM,circle=True),
        mode=Types.SectionMode.RIGHT
    )
) # 设置小图+圆角

image-20230906145208958

更多大小设置请参考 Types.Size 的成员。

# 6.3 多图

使用ImageGroup聚合显示多张图片

# 多图
c7 = Card(
    Module.ImageGroup(
        Element.Image(src=msg.author.avatar),
        Element.Image(src=msg.author.avatar),
        Element.Image(src=msg.author.avatar),
        Element.Image(src=msg.author.avatar),
    )
)

图片数量不同,显示的效果也不同

image-20230906145615310

image-20230906145625103

# 7.按钮

# 7.1 参数说明

按钮包含3个参数

  • 按钮显示的文字值
  • 按钮的value(可以是你设定的字符串,也可以是一个网页链接)
  • 点击按钮触发的动作(RETUAN_VAL代表返回事件给机器人,LINK代表跳转链接)
  • 按钮主题Theme(按钮颜色,相见Types.Theme)

# 7.2 多按钮示例

如下是一个多按钮的示例代码

c8 = Card(
    Module.ActionGroup(
        Element.Button("按钮文字1",value='按钮值1',click=Types.Click.RETURN_VAL,theme=Types.Theme.INFO),
        Element.Button("按钮文字2",value='按钮值2',click=Types.Click.RETURN_VAL,theme=Types.Theme.DANGER),
        Element.Button("按钮文字3",value='https://khl-py.eu.org/',click=Types.Click.LINK,theme=Types.Theme.SECONDARY)
    )
)

消息发送后的效果如下

image-20230906150252169

最后一个按钮点击会直接跳转到预先设定好的网页链接,这里不做演示;

# 7.3 按钮点击事件

前两个按钮我都设置成了RETURN_VAL,当用户点击这个按钮的时候,会触发一个BUTTON_CLICK事件并发送给机器人,我们可以使用on_event监听这个时间,并在收到对应的按钮点击事件后,触发操作(比如更新卡片消息实现类似翻页的效果)

@bot.on_event(EventTypes.MESSAGE_BTN_CLICK)
async def btn_click_event(b:Bot,e:Event):
    """按钮点击事件"""
    print(e.target_id)
    print(e.body,"\n")

两个按钮的事件输出如下,其中e.body['value']就包含了我们在按钮中设置的value值,您可以根据这个事件的body,来进行对应的一些操作;如果你认为单一字符串的value不符合要求,也可以将按钮的value设置为json字符串以实现更多功能;

3734705365
{'value': '按钮值1', 'msg_id': '382e4334-cf39-4f82-a9b8-18c97faa54fd', 'user_id': '1961572535', 'target_id': '9534308950818813', 'channel_type': 'GROUP', 'user_info': {'id': '1961572535', 'username': 'MUXUE', 'identify_num': '7134', 'online': True, 'os': 'Websocket', 'status': 1, 'avatar': 'https://img.kookapp.cn/avatars/2022-09/IAzzZG7v8A06j06j.png?x-oss-process=style/icon', 'vip_avatar': 'https://img.kookapp.cn/avatars/2022-09/IAzzZG7v8A06j06j.png?x-oss-process=style/icon', 'banner': '', 'nickname': 'MUXUE', 'roles': [4693884], 'is_vip': False, 'vip_amp': False, 'is_ai_reduce_noise': True, 'is_personal_card_bg': False, 'bot': False, 'decorations_id_map': None, 'mobile_verified': True, 'is_sys': False, 'joined_at': 1658024340000, 'active_time': 1693983764680}, 'guild_id': '3280131482359624'}   

3734705365
{'value': '按钮值2', 'msg_id': '382e4334-cf39-4f82-a9b8-18c97faa54fd', 'user_id': '1961572535', 'target_id': '9534308950818813', 'channel_type': 'GROUP', 'user_info': {'id': '1961572535', 'username': 'MUXUE', 'identify_num': '7134', 'online': True, 'os': 'Websocket', 'status': 1, 'avatar': 'https://img.kookapp.cn/avatars/2022-09/IAzzZG7v8A06j06j.png?x-oss-process=style/icon', 'vip_avatar': 'https://img.kookapp.cn/avatars/2022-09/IAzzZG7v8A06j06j.png?x-oss-process=style/icon', 'banner': '', 'nickname': 'MUXUE', 'roles': [4693884], 'is_vip': False, 'vip_amp': False, 'is_ai_reduce_noise': True, 'is_personal_card_bg': False, 'bot': False, 'decorations_id_map': None, 'mobile_verified': True, 'is_sys': False, 'joined_at': 1658024340000, 'active_time': 1693983764680}, 'guild_id': '3280131482359624'} 

# 7.4 按钮+文字

用法和图片+文字很类似

        c9 = Card(
            Module.Section(
                Element.Text("这里是文字", type=Types.Text.KMD),
                Element.Button(
                    "这里是按钮",
                    value="按钮值1",
                    click=Types.Click.RETURN_VAL,
                    theme=Types.Theme.INFO,
                ),
            )
        )

image-20230906151205370

# 8.倒计时

倒计时分为3种不同的形式,在卡片编辑器中预览如下

image-20230906151356115

在khl.py中,对应的模块是Module.Countdown,这里传入一个datetime类型作为倒计时的时长,传入mode指定倒计时的三种模式

c10 = Card(
    Module.Countdown(
        datetime.now() + timedelta(seconds=360000), mode=Types.CountdownMode.DAY
    ),
    Module.Countdown(
        datetime.now() + timedelta(seconds=3600), mode=Types.CountdownMode.HOUR
    ),
    Module.Countdown(
        datetime.now() + timedelta(seconds=3600), mode=Types.CountdownMode.SECOND
    )
)

image-20230906151543635

你还可以传入一个start,指定倒计时是什么时候开始的,比如30s前开始倒计时,还剩余60秒

        c11 = Card(
            Module.Countdown(
                datetime.now() + timedelta(seconds=60),
                mode=Types.CountdownMode.SECOND,
                start=datetime.now() - timedelta(seconds=30),
            )
        )

这时候进度条就会变成一个90s的条,并从60s的位置开始继续倒计时

image-20230906151945434

上次更新: 2023/09/29, 16:21:33
上传和发送文件或图片
获取频道对象

← 上传和发送文件或图片 获取频道对象→

Theme by Vdoing | Copyright © 2023-2025 khl.py | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式