调整 ytpgif 使用共用方法读取图片
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-10-09 19:56:16 +08:00
parent c35ee57976
commit b4e400b626

View File

@ -1,9 +1,9 @@
import os
import tempfile
from io import BytesIO
from typing import Optional
from PIL import Image, ImageSequence
from PIL import Image
from nonebot.adapters import Event as BaseEvent
from nonebot.adapters import Bot as BaseBot
from nonebot.plugin import PluginMetadata
from nonebot_plugin_alconna import (
Alconna,
@ -12,6 +12,9 @@ from nonebot_plugin_alconna import (
UniMessage,
on_alconna,
)
from returns.result import Failure, Success
from konabot.common.nb.extract_image import extract_image_from_message
__plugin_meta__ = PluginMetadata(
name="ytpgif",
@ -60,7 +63,7 @@ async def get_image_url(event: BaseEvent) -> Optional[str]:
if seg.type == "image" and seg.data.get("url"):
return str(seg.data["url"])
if hasattr(event, "reply") and (reply := event.reply):
if hasattr(event, "reply") and (reply := getattr(event, "reply")):
reply_msg = reply.message
for seg in reply_msg:
if seg.type == "image" and seg.data.get("url"):
@ -89,7 +92,7 @@ def resize_frame(frame: Image.Image) -> Image.Image:
@ytpgif_cmd.handle()
async def handle_ytpgif(event: BaseEvent, speed: float = 1.0):
async def handle_ytpgif(event: BaseEvent, bot: BaseBot, speed: float = 1.0):
# === 校验 speed 范围 ===
if not (MIN_SPEED <= speed <= MAX_SPEED):
await ytpgif_cmd.send(
@ -97,40 +100,26 @@ async def handle_ytpgif(event: BaseEvent, speed: float = 1.0):
)
return
img_url = await get_image_url(event)
if not img_url:
match await extract_image_from_message(event.get_message(), event, bot):
case Success(img):
src_img = img
case Failure(msg):
await ytpgif_cmd.send(
await UniMessage.text(
"请发送一张图片或回复一张图片来生成镜像动图。"
).export()
await UniMessage.text(msg).export()
)
return
try:
image_data = await download_image(img_url)
except Exception as e:
print(f"[YTPGIF] 下载失败: {e}")
await ytpgif_cmd.send(
await UniMessage.text("❌ 图片下载失败,请重试。").export()
)
case _:
return
input_path = output_path = None
try:
with tempfile.NamedTemporaryFile(delete=False, suffix=".gif") as tmp_in:
tmp_in.write(image_data)
input_path = tmp_in.name
with tempfile.NamedTemporaryFile(delete=False, suffix=".gif") as tmp_out:
output_path = tmp_out.name
with Image.open(input_path) as src_img:
# === 判断是否为动图 ===
try:
n_frames = getattr(src_img, "n_frames", 1)
is_animated = n_frames > 1
except Exception:
is_animated = False
n_frames = 1
output_frames = []
output_durations_ms = []
@ -190,7 +179,7 @@ async def handle_ytpgif(event: BaseEvent, speed: float = 1.0):
for img, dur in frames_with_duration:
if accumulated + dur > max_dur or frame_count >= MAX_FRAMES_PER_SEGMENT:
break
flipped = img.transpose(Image.FLIP_LEFT_RIGHT)
flipped = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
output_frames.append(flipped)
output_durations_ms.append(int(dur * 1000))
accumulated += dur
@ -205,7 +194,7 @@ async def handle_ytpgif(event: BaseEvent, speed: float = 1.0):
duration_ms = int(interval_sec * 1000)
frame1 = resized_frame
frame2 = resized_frame.transpose(Image.FLIP_LEFT_RIGHT)
frame2 = resized_frame.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
output_frames = [frame1, frame2]
output_durations_ms = [duration_ms, duration_ms]
@ -247,22 +236,12 @@ async def handle_ytpgif(event: BaseEvent, speed: float = 1.0):
if need_transparency:
save_kwargs["transparency"] = 0
output_frames[0].save(output_path, **save_kwargs)
# 发送结果
with open(output_path, "rb") as f:
result_image = UniMessage.image(raw=f.read())
bio = BytesIO()
output_frames[0].save(bio, **save_kwargs)
result_image = UniMessage.image(raw=bio)
await ytpgif_cmd.send(await result_image.export())
except Exception as e:
print(f"[YTPGIF] 处理失败: {e}")
await ytpgif_cmd.send(
await UniMessage.text("❌ 处理失败,可能是图片格式不支持、文件损坏或过大。").export()
)
finally:
for path in filter(None, [input_path, output_path]):
if os.path.exists(path):
try:
os.unlink(path)
except: # noqa
pass