Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions src/nonebot_plugin_parser/parsers/bilibili/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ async def _parse_short_link(self, searched: Match[str]):
return await self.parse_with_redirect(url)

@handle("BV", r"^(?P<bvid>BV[0-9a-zA-Z]{10})(?:\s)?(?P<page_num>\d{1,3})?$")
@handle("/BV", r"bilibili\.com(?:/video)?/(?P<bvid>BV[0-9a-zA-Z]{10})(?:\?p=(?P<page_num>\d{1,3}))?")
@handle(
"/BV",
r"bilibili\.com(?:/video)?/(?P<bvid>BV[0-9a-zA-Z]{10})(?:\?p=(?P<page_num>\d{1,3}))?",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里为什么要换行

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

格式化插件自动的

)
async def _parse_bv(self, searched: Match[str]):
"""解析视频信息"""
bvid = str(searched.group("bvid"))
Expand All @@ -57,7 +60,10 @@ async def _parse_bv(self, searched: Match[str]):
return await self.parse_video(bvid=bvid, page_num=page_num)

@handle("av", r"^av(?P<avid>\d{6,})(?:\s)?(?P<page_num>\d{1,3})?$")
@handle("/av", r"bilibili\.com(?:/video)?/av(?P<avid>\d{6,})(?:\?p=(?P<page_num>\d{1,3}))?")
@handle(
"/av",
r"bilibili\.com(?:/video)?/av(?P<avid>\d{6,})(?:\?p=(?P<page_num>\d{1,3}))?",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)
async def _parse_av(self, searched: Match[str]):
"""解析视频信息"""
avid = int(searched.group("avid"))
Expand All @@ -67,10 +73,11 @@ async def _parse_av(self, searched: Match[str]):

@handle("/dynamic/", r"bilibili\.com/dynamic/(?P<dynamic_id>\d+)")
@handle("t.bili", r"t\.bilibili\.com/(?P<dynamic_id>\d+)")
@handle("/opus/", r"bilibili\.com/opus/(?P<dynamic_id>\d+)")
async def _parse_dynamic(self, searched: Match[str]):
"""解析动态信息"""
dynamic_id = int(searched.group("dynamic_id"))
return await self.parse_dynamic(dynamic_id)
return await self.parse_dynamic_or_opus(dynamic_id)

@handle("live.bili", r"live\.bilibili\.com/(?P<room_id>\d+)")
async def _parse_live(self, searched: Match[str]):
Expand All @@ -88,13 +95,7 @@ async def _parse_favlist(self, searched: Match[str]):
async def _parse_read(self, searched: Match[str]):
"""解析专栏信息"""
read_id = int(searched.group("read_id"))
return await self.parse_read_with_opus(read_id)

@handle("/opus/", r"bilibili\.com/opus/(?P<opus_id>\d+)")
async def _parse_opus(self, searched: Match[str]):
Comment thread
molanp marked this conversation as resolved.
"""解析图文动态信息"""
opus_id = int(searched.group("opus_id"))
return await self.parse_opus(opus_id)
return await self.parse_read(read_id)

async def parse_video(
self,
Expand Down Expand Up @@ -167,8 +168,8 @@ async def download_video():
extra={"info": ai_summary},
)

async def parse_dynamic(self, dynamic_id: int):
"""解析动态信息
async def parse_dynamic_or_opus(self, dynamic_id: int):
"""解析动态和图文信息

Args:
url (str): 动态链接
Expand All @@ -178,6 +179,8 @@ async def parse_dynamic(self, dynamic_id: int):
from .dynamic import DynamicData

dynamic = Dynamic(dynamic_id, await self.credential)
if await dynamic.is_article():
return await self._parse_opus_obj(dynamic.turn_to_opus())
dynamic_info = convert(await dynamic.get_info(), DynamicData).item

author = self.create_author(dynamic_info.name, dynamic_info.avatar)
Expand Down Expand Up @@ -205,7 +208,7 @@ async def parse_opus(self, opus_id: int):
opus = Opus(opus_id, await self.credential)
return await self._parse_opus_obj(opus)

async def parse_read_with_opus(self, read_id: int):
async def parse_read(self, read_id: int):
"""解析专栏信息, 使用 Opus 接口

Args:
Expand Down
10 changes: 8 additions & 2 deletions src/nonebot_plugin_parser/parsers/bilibili/dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ class OpusContent(Struct):
class DynamicMajor(Struct):
"""动态主要内容"""

type: str
type: str | None = None
archive: VideoArchive | None = None
opus: OpusContent | None = None
desc: OpusSummary | None = None

@property
def title(self) -> str | None:
Expand All @@ -81,6 +82,8 @@ def text(self) -> str | None:
return self.archive.desc
elif self.type == "MAJOR_TYPE_OPUS" and self.opus:
return self.opus.summary.text
elif self.desc:
return self.desc.text
return None

@property
Expand Down Expand Up @@ -126,7 +129,10 @@ def pub_ts(self) -> int:
def major_info(self) -> dict[str, Any] | None:
"""获取主要内容信息"""
if self.module_dynamic:
return self.module_dynamic.get("major")
if major := self.module_dynamic.get("major"):
return major
# 转发类型动态没有 major
return self.module_dynamic
return None


Expand Down
53 changes: 46 additions & 7 deletions src/nonebot_plugin_parser/renders/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ class FontSet:
def new(cls, font_path: Path):
font_infos: dict[str, FontInfo] = {}
for name, size, fill in cls._FONT_INFOS:
font = ImageFont.truetype(font_path, size)
with open(font_path, "rb") as f:
font_bytes = BytesIO(f.read())
font = ImageFont.truetype(font_bytes, size, encoding="utf-8")
Comment thread
molanp marked this conversation as resolved.
Outdated
height = get_font_height(font)
font_infos[name] = FontInfo(
font=font,
Expand Down Expand Up @@ -360,10 +362,23 @@ async def text(
) -> int:
"""绘制文本"""
if emosvg is not None:
emosvg.text(ctx.image, xy, lines, font.font, fill=font.fill, line_height=font.line_height)
emosvg.text(
ctx.image,
xy,
lines,
font.font,
fill=font.fill,
line_height=font.line_height,
)
else:
await Apilmoji.text(
ctx.image, xy, lines, font.font, fill=font.fill, line_height=font.line_height, source=cls.EMOJI_SOURCE
ctx.image,
xy,
lines,
font.font,
fill=font.fill,
line_height=font.line_height,
source=cls.EMOJI_SOURCE,
)
return font.line_height * len(lines)

Expand Down Expand Up @@ -1217,10 +1232,34 @@ def _draw_rounded_rectangle_border(
draw.rectangle((x2 - width, y1 + radius, x2, y2 - radius), fill=border_color) # 右

# 绘制四个圆角边框
draw.arc((x1, y1, x1 + 2 * radius, y1 + 2 * radius), 180, 270, fill=border_color, width=width)
draw.arc((x2 - 2 * radius, y1, x2, y1 + 2 * radius), 270, 360, fill=border_color, width=width)
draw.arc((x1, y2 - 2 * radius, x1 + 2 * radius, y2), 90, 180, fill=border_color, width=width)
draw.arc((x2 - 2 * radius, y2 - 2 * radius, x2, y2), 0, 90, fill=border_color, width=width)
draw.arc(
(x1, y1, x1 + 2 * radius, y1 + 2 * radius),
180,
270,
fill=border_color,
width=width,
Comment thread
molanp marked this conversation as resolved.
Outdated
)
draw.arc(
(x2 - 2 * radius, y1, x2, y1 + 2 * radius),
270,
360,
fill=border_color,
width=width,
)
draw.arc(
(x1, y2 - 2 * radius, x1 + 2 * radius, y2),
90,
180,
fill=border_color,
width=width,
)
draw.arc(
(x2 - 2 * radius, y2 - 2 * radius, x2, y2),
0,
90,
fill=border_color,
width=width,
)

def _wrap_text(self, text: str, max_width: int, font_info: FontInfo) -> list[str]:
"""使用 emoji.emoji_list 优化的文本自动换行算法,正确处理组合 emoji
Expand Down
47 changes: 5 additions & 42 deletions tests/parsers/test_bilibili.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async def test_read():
parser = BilibiliParser()
_, searched = parser.search_url(url)
read_id = int(searched.group("read_id"))
result = await parser.parse_read_with_opus(read_id)
result = await parser.parse_read(read_id)
logger.debug(f"result: {result}")
assert result.title, "标题为空"
assert result.author, "作者为空"
Expand All @@ -60,58 +60,21 @@ async def test_read():


@pytest.mark.asyncio
async def test_opus():
async def test_dynamic():
from nonebot_plugin_parser.parsers import BilibiliParser

opus_urls = [
dynamic_urls = [
"https://t.bilibili.com/1120105154190770281",
"https://www.bilibili.com/opus/998440765151510535",
"https://www.bilibili.com/opus/1040093151889457152",
]

parser = BilibiliParser()

async def test_parse_opus(opus_url: str) -> None:
_, searched = parser.search_url(opus_url)
opus_id = int(searched.group("opus_id"))
try:
result = await parser.parse_opus(opus_id)
except Exception as e:
pytest.skip(f"{opus_url} | opus 解析失败: {e} (风控)")

assert result.contents, "内容为空"
for content in result.contents:
path = await content.get_path()
assert path.exists(), "内容不存在"

assert result.author, "作者为空"
avatar_path = await result.author.get_avatar_path()
assert avatar_path, "头像不存在"
assert avatar_path.exists(), "头像不存在"

graphics_contents = result.graphics_contents
assert graphics_contents, "图文内容为空"

for graphics_content in graphics_contents:
path = await graphics_content.get_path()
assert path.exists(), "图文内容不存在"

await asyncio.gather(*[test_parse_opus(opus_url) for opus_url in opus_urls])
logger.success("B站动态解析成功")


@pytest.mark.asyncio
async def test_dynamic():
from nonebot_plugin_parser.parsers import BilibiliParser

dynamic_urls = ["https://t.bilibili.com/1120105154190770281"]

parser = BilibiliParser()

async def test_parse_dynamic(dynamic_url: str) -> None:
_, searched = parser.search_url(dynamic_url)
dynamic_id = int(searched.group("dynamic_id"))
result = await parser.parse_dynamic(dynamic_id)
assert result.title, "标题为空"
result = await parser.parse_dynamic_or_opus(dynamic_id)
assert result.author, "作者为空"
avatar_path = await result.author.get_avatar_path()
assert avatar_path, "头像不存在"
Expand Down
Loading