Skip to content

Commit 8a5148b

Browse files
committed
fix: OneBot通知支持本地海报图片转base64发送
1 parent b8a8c8e commit 8a5148b

1 file changed

Lines changed: 53 additions & 3 deletions

File tree

  • backend/src/module/notification/providers

backend/src/module/notification/providers/onebot.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
Documentation: https://github.com/botuniverse/onebot-11
77
"""
88

9+
import base64
910
import json
1011
import logging
12+
import os
1113
from typing import TYPE_CHECKING
1214

1315
from module.models.bangumi import Notification
@@ -78,6 +80,53 @@ async def _post_json(self, url: str, data: dict) -> object:
7880
logger.warning(f"[OneBot] Request failed: {e}")
7981
return None
8082

83+
def _get_image_file(self, poster_path: str) -> str | None:
84+
"""Convert poster_path to a OneBot-compatible image file reference.
85+
86+
Handles three cases:
87+
1. Remote URL (contains ://) - use as-is
88+
2. Local file path - read and convert to base64
89+
3. Invalid/missing - return None
90+
91+
Args:
92+
poster_path: The poster path or URL from the database.
93+
94+
Returns:
95+
A OneBot-compatible file string (URL or base64), or None.
96+
"""
97+
if not poster_path or poster_path in ("", "https://mikanani.me"):
98+
return None
99+
100+
# If it's a remote URL, use it directly
101+
if "://" in poster_path:
102+
return poster_path
103+
104+
# Otherwise, try to read it as a local file
105+
# The path is relative to the data directory (e.g. "posters/xxx.jpg")
106+
local_path = os.path.join("data", poster_path.lstrip("/"))
107+
if os.path.exists(local_path):
108+
try:
109+
with open(local_path, "rb") as f:
110+
img_data = f.read()
111+
img_b64 = base64.b64encode(img_data).decode("ascii")
112+
# Determine MIME type from extension
113+
ext = os.path.splitext(local_path)[1].lower()
114+
mime_map = {
115+
".jpg": "image/jpeg",
116+
".jpeg": "image/jpeg",
117+
".png": "image/png",
118+
".gif": "image/gif",
119+
".webp": "image/webp",
120+
}
121+
mime = mime_map.get(ext, "image/jpeg")
122+
return f"base64://{img_b64}"
123+
except Exception as e:
124+
logger.warning(f"[OneBot] Failed to read local image {local_path}: {e}")
125+
return None
126+
else:
127+
logger.warning(f"[OneBot] Local image not found: {local_path}")
128+
return None
129+
81130
def _build_payload(
82131
self, text: str, poster_path: str = None
83132
) -> str | list:
@@ -89,14 +138,15 @@ def _build_payload(
89138
90139
Args:
91140
text: The text message content.
92-
poster_path: Optional URL to a poster image.
141+
poster_path: Optional URL or local path to a poster image.
93142
94143
Returns:
95144
A string (plain text) or list (message segments).
96145
"""
97-
if poster_path and poster_path not in ("", "https://mikanani.me"):
146+
image_file = self._get_image_file(poster_path) if poster_path else None
147+
if image_file:
98148
return [
99-
{"type": "image", "data": {"file": poster_path}},
149+
{"type": "image", "data": {"file": image_file}},
100150
{"type": "text", "data": {"text": text}},
101151
]
102152
return text

0 commit comments

Comments
 (0)