259 lines
7.0 KiB
Markdown
259 lines
7.0 KiB
Markdown
# 媒体 API
|
||
|
||
这一页讲的是怎么处理图片、语音等媒体文件。虽然方法不多,但都很实用。
|
||
|
||
## 能力检查
|
||
|
||
### `can_send_image` - 检查是否可以发送图片
|
||
|
||
```python
|
||
async def can_send_image(self) -> Dict[str, Any]
|
||
```
|
||
|
||
检查当前上下文是否允许发送图片。
|
||
|
||
**返回值:**
|
||
- 包含检查结果的字典,通常有 `yes` 或 `no` 字段
|
||
|
||
**示例:**
|
||
```python
|
||
@matcher.command("sendpic")
|
||
async def handle_sendpic(event: MessageEvent, args: str):
|
||
# 先检查能不能发图片
|
||
result = await event.bot.can_send_image()
|
||
|
||
if result.get("yes"):
|
||
# 可以发图片
|
||
await event.reply(MessageSegment.image("https://example.com/image.jpg"))
|
||
else:
|
||
# 不能发图片
|
||
await event.reply("当前环境不支持发送图片")
|
||
```
|
||
|
||
### `can_send_record` - 检查是否可以发送语音
|
||
|
||
```python
|
||
async def can_send_record(self) -> Dict[str, Any]
|
||
```
|
||
|
||
检查当前上下文是否允许发送语音消息。
|
||
|
||
**示例:**
|
||
```python
|
||
result = await bot.can_send_record()
|
||
if result.get("yes"):
|
||
print("可以发语音")
|
||
else:
|
||
print("不能发语音")
|
||
```
|
||
|
||
## 图片信息
|
||
|
||
### `get_image` - 获取图片信息
|
||
|
||
```python
|
||
async def get_image(self, file: str) -> Dict[str, Any]
|
||
```
|
||
|
||
获取图片的详细信息,比如大小、尺寸、MD5 等。
|
||
|
||
**参数:**
|
||
- `file`: 图片文件名、路径或 URL
|
||
|
||
**返回值:**
|
||
- 包含图片信息的字典
|
||
|
||
**示例:**
|
||
```python
|
||
@matcher.command("imageinfo")
|
||
async def handle_imageinfo(event: MessageEvent):
|
||
# 检查消息中是否有图片
|
||
for segment in event.message:
|
||
if segment.type == "image":
|
||
file = segment.data.get("file", "")
|
||
if file:
|
||
# 获取图片信息
|
||
info = await event.bot.get_image(file)
|
||
await event.reply(
|
||
f"图片信息:\n"
|
||
f"大小: {info.get('size', '未知')} 字节\n"
|
||
f"尺寸: {info.get('width', '?')}x{info.get('height', '?')}\n"
|
||
f"MD5: {info.get('md5', '未知')}"
|
||
)
|
||
return
|
||
|
||
await event.reply("消息中没有图片")
|
||
```
|
||
|
||
## 实际应用示例
|
||
|
||
### 图片转发器
|
||
|
||
```python
|
||
@matcher.command("forwardimage")
|
||
async def handle_forwardimage(event: MessageEvent, args: str):
|
||
"""
|
||
将收到的图片转发到指定群
|
||
用法: /forwardimage 群号
|
||
"""
|
||
if not args.isdigit():
|
||
await event.reply("参数错误,需要群号")
|
||
return
|
||
|
||
target_group = int(args)
|
||
|
||
# 查找消息中的图片
|
||
images = []
|
||
for segment in event.message:
|
||
if segment.type == "image":
|
||
images.append(segment)
|
||
|
||
if not images:
|
||
await event.reply("消息中没有图片")
|
||
return
|
||
|
||
# 检查是否能发图片到目标群
|
||
can_send = await event.bot.can_send_image()
|
||
if not can_send.get("yes"):
|
||
await event.reply("当前环境不支持发送图片")
|
||
return
|
||
|
||
# 转发所有图片
|
||
for image in images:
|
||
await event.bot.send_group_msg(target_group, image)
|
||
await asyncio.sleep(0.5) # 避免发送太快
|
||
|
||
await event.reply(f"已转发 {lenimages()} 张图片到群 {target_group}")
|
||
```
|
||
|
||
### 图片信息查询插件
|
||
|
||
```python
|
||
@matcher.on_event(GroupMessageEvent)
|
||
async def handle_image_autoinfo(event: GroupMessageEvent):
|
||
"""
|
||
自动回复图片信息(当有人发图片时)
|
||
"""
|
||
# 只处理包含图片的消息
|
||
images = [seg for seg in event.message if seg.type == "image"]
|
||
if not images:
|
||
return
|
||
|
||
# 只处理第一张图片(避免消息太长)
|
||
image_seg = images[0]
|
||
file = image_seg.data.get("file", "")
|
||
|
||
if not file:
|
||
return
|
||
|
||
try:
|
||
# 获取图片信息
|
||
info = await event.bot.get_image(file)
|
||
|
||
# 构建回复消息
|
||
msg = "📷 图片信息:n\"
|
||
if "size" in info:
|
||
size_kb = info["size"] / 1024
|
||
msg += f"大小: {size_kb:.1f} KB\n"
|
||
if "width" in info and "height" in info:
|
||
msg += f"尺寸: {info['width']}×{info['height']}\n"
|
||
if "md5" in info:
|
||
msg += f"MD5: {info['md5'][:8]}...\n"
|
||
|
||
await event.reply(msg)
|
||
except Exception as e:
|
||
# 获取图片信息失败,静默处理
|
||
pass
|
||
```
|
||
|
||
### 图片发送安全检查
|
||
|
||
```python
|
||
async def safe_send_image(bot, target_id, image_url, is_group=True):
|
||
"""
|
||
安全发送图片:先检查是否能发,再发送
|
||
"""
|
||
# 检查发送能力
|
||
can_send = await bot.can_send_image()
|
||
if not can_send.get("yes"):
|
||
return False, "当前环境不支持发送图片"
|
||
|
||
# 检查图片是否存在(简单检查)
|
||
if not image_url:
|
||
return False, "图片URL为空"
|
||
|
||
try:
|
||
# 发送图片
|
||
if is_group:
|
||
await bot.send_group_msg(target_id, MessageSegment.image(image_url))
|
||
else:
|
||
await bot.send_private_msg(target_id, MessageSegment.image(image_url))
|
||
return True, "图片发送成功"
|
||
except Exception as e:
|
||
return False, f"发送失败: {e}"
|
||
|
||
@matcher.command("safepic")
|
||
async def handle_safepic(event: MessageEvent, args: str):
|
||
"""
|
||
安全发送图片示例
|
||
"""
|
||
if not args:
|
||
await event.reply("需要图片URL")
|
||
return
|
||
|
||
# 是判断群聊还是私聊
|
||
is_group = hasattr(event, "group_id") and event.group_id
|
||
|
||
if is_group:
|
||
target_id = event.group_id
|
||
else:
|
||
target_id = event.user_id
|
||
|
||
# 安全发送
|
||
success, message = await safe_send_image(
|
||
event.bot, target_id, args, is_group
|
||
)
|
||
|
||
if not success:
|
||
await event.reply(message)
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **客户端支持**: 不是所有 OneBot 客户端都完全支持媒体 API。
|
||
2. **网络限制**: 发送图片和语音可能受网络环境限制。
|
||
3. **文件大小**: 图片和语音文件有大小限制,太大的文件可能发送失败。
|
||
4. **缓存**: 图片默认会缓存,重复发送同一图片会更快。
|
||
5. **安全性**: 不要发送可疑或非法内容。
|
||
|
||
## 常见问题
|
||
|
||
### Q: 为什么 `can_send_image` 总是返回可以?
|
||
A: 这取决于 OneBot 客户端的实现。有些客户端可能不检查实际能力,总是返回可以。
|
||
|
||
### Q: 怎么发送本地图片?
|
||
A: 使用 `file://` 协议或直接使用本地路径:
|
||
```python
|
||
# 本地文件路径
|
||
image = MessageSegment.image("file:///path/to/image.jpg")
|
||
# 或者(取决于客户端)
|
||
image = MessageSegment.image("/path/to/image.jpg")
|
||
```
|
||
|
||
### Q: 怎么发送语音消息?
|
||
A: NEO Bot 目前没有封装发送语音的 API,但你可以通过 `call_api` 直接调用:
|
||
```python
|
||
await bot.call_api("send_group_msg", {
|
||
"group_id": 123456,
|
||
"message": [{
|
||
"type": "record",
|
||
"data": {"file": "http://example.com/voice.amr"}
|
||
}]
|
||
})
|
||
```
|
||
|
||
## 下一步
|
||
|
||
- [消息 API](./message.md): 怎么发消息、撤回消息,包含消息段的使用
|
||
- [群组 API](./group.md): 管理群聊相关功能
|
||
- [好友 API](./friend.md): 管理好友相关功能 |