nonebot-plugin-parser 2.2.5__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/PKG-INFO +3 -3
  2. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/README.md +1 -1
  3. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/pyproject.toml +7 -7
  4. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/config.py +1 -2
  5. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/common.py +69 -73
  6. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/__init__.py +0 -0
  7. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/constants.py +0 -0
  8. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/download/__init__.py +0 -0
  9. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/download/task.py +0 -0
  10. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/download/ytdlp.py +0 -0
  11. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/exception.py +0 -0
  12. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/helper.py +0 -0
  13. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/matchers/__init__.py +0 -0
  14. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/matchers/filter.py +0 -0
  15. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/matchers/rule.py +0 -0
  16. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/__init__.py +0 -0
  17. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/acfun.py +0 -0
  18. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/base.py +0 -0
  19. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/__init__.py +0 -0
  20. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/article.py +0 -0
  21. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/common.py +0 -0
  22. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/dynamic.py +0 -0
  23. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/favlist.py +0 -0
  24. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/live.py +0 -0
  25. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/opus.py +0 -0
  26. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/bilibili/video.py +0 -0
  27. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/cookie.py +0 -0
  28. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/data.py +0 -0
  29. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/douyin/__init__.py +0 -0
  30. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/douyin/slides.py +0 -0
  31. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/douyin/video.py +0 -0
  32. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/kuaishou.py +0 -0
  33. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/nga.py +0 -0
  34. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/tiktok.py +0 -0
  35. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/twitter.py +0 -0
  36. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/weibo.py +0 -0
  37. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/xiaohongshu.py +0 -0
  38. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/parsers/youtube.py +0 -0
  39. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/__init__.py +0 -0
  40. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/base.py +0 -0
  41. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/default.py +0 -0
  42. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/HYSongYunLangHeiW-1.ttf +0 -0
  43. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/bilibili.png +0 -0
  44. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/douyin.png +0 -0
  45. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/kuaishou.png +0 -0
  46. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/media_button.png +0 -0
  47. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/tiktok.png +0 -0
  48. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/twitter.png +0 -0
  49. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/weibo.png +0 -0
  50. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/xiaohongshu.png +0 -0
  51. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/resources/youtube.png +0 -0
  52. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/templates/weibo.html.jinja +0 -0
  53. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/renders/weibo.py +0 -0
  54. {nonebot_plugin_parser-2.2.5 → nonebot_plugin_parser-2.3.0}/src/nonebot_plugin_parser/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nonebot-plugin-parser
3
- Version: 2.2.5
3
+ Version: 2.3.0
4
4
  Summary: NoneBot2 链接分享解析 Alconna 版, 通用媒体卡片渲染(PIL 实现), 支持 B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun/nga
5
5
  Keywords: acfun,bilibili,douyin,kuaishou,nga,nonebot,nonebot2,tiktok,twitter,video,weibo,xiaohongshu,youtube
6
6
  Author: fllesser
@@ -26,9 +26,9 @@ Requires-Dist: aiofiles>=25.1.0
26
26
  Requires-Dist: curl-cffi>=0.13.0,<1.0.0
27
27
  Requires-Dist: httpx>=0.27.2,<1.0.0
28
28
  Requires-Dist: msgspec>=0.20.0,<1.0.0
29
+ Requires-Dist: apilmoji[tqdm]>=0.1.2,<1.0.0
29
30
  Requires-Dist: beautifulsoup4>=4.12.0,<5.0.0
30
31
  Requires-Dist: bilibili-api-python>=17.4.0,<18.0.0
31
- Requires-Dist: pilmoji-for-parser[tqdm]>=0.2.0,<1.0.0
32
32
  Requires-Dist: nonebot-plugin-alconna>=0.59.4,<1.0.0
33
33
  Requires-Dist: nonebot-plugin-apscheduler>=0.5.0,<1.0.0
34
34
  Requires-Dist: nonebot-plugin-localstore>=0.7.4,<1.0.0
@@ -260,7 +260,7 @@ parser_need_forward_contents=True
260
260
 
261
261
  # [可选] emoji 渲染 CDN
262
262
  # 例如 ELK_SH_CDN = "https://emojicdn.elk.sh", MQRIO_DEV_CDN = "https://emoji-cdn.mqrio.dev"
263
- parser_emoji_cdn=ELK_SH_CDN
263
+ parser_emoji_cdn="https://emojicdn.elk.sh"
264
264
 
265
265
  # [可选] emoji 渲染样式 "apple", "google", "twitter", "facebook"(默认)
266
266
  parser_emoji_style="facebook"
@@ -212,7 +212,7 @@ parser_need_forward_contents=True
212
212
 
213
213
  # [可选] emoji 渲染 CDN
214
214
  # 例如 ELK_SH_CDN = "https://emojicdn.elk.sh", MQRIO_DEV_CDN = "https://emoji-cdn.mqrio.dev"
215
- parser_emoji_cdn=ELK_SH_CDN
215
+ parser_emoji_cdn="https://emojicdn.elk.sh"
216
216
 
217
217
  # [可选] emoji 渲染样式 "apple", "google", "twitter", "facebook"(默认)
218
218
  parser_emoji_style="facebook"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-parser"
3
- version = "2.2.5"
3
+ version = "2.3.0"
4
4
  description = "NoneBot2 链接分享解析 Alconna 版, 通用媒体卡片渲染(PIL 实现), 支持 B站/抖音/快手/微博/小红书/youtube/tiktok/twitter/acfun/nga"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -46,9 +46,9 @@ dependencies = [
46
46
  "curl_cffi>=0.13.0,<1.0.0",
47
47
  "httpx>=0.27.2,<1.0.0",
48
48
  "msgspec>=0.20.0,<1.0.0",
49
+ "apilmoji[tqdm]>=0.1.2,<1.0.0",
49
50
  "beautifulsoup4>=4.12.0,<5.0.0",
50
51
  "bilibili-api-python>=17.4.0,<18.0.0",
51
- "pilmoji-for-parser[tqdm]>=0.2.0,<1.0.0",
52
52
  "nonebot-plugin-alconna>=0.59.4,<1.0.0",
53
53
  "nonebot-plugin-apscheduler>=0.5.0,<1.0.0",
54
54
  "nonebot-plugin-localstore>=0.7.4,<1.0.0",
@@ -105,12 +105,12 @@ conflicts = [
105
105
  ]
106
106
 
107
107
  [tool.uv.sources]
108
- nonebug = { git = "https://github.com/fllesser/nonebug", rev = "dev/migrate-uv" }
108
+ nonebug = { git = "https://github.com/nonebot/nonebug" }
109
109
 
110
110
  [tool.bumpversion]
111
111
  tag = true
112
112
  commit = true
113
- current_version = "2.2.5"
113
+ current_version = "2.3.0"
114
114
  message = "release: bump vesion from {current_version} to {new_version}"
115
115
 
116
116
  [[tool.bumpversion.files]]
@@ -136,9 +136,9 @@ adapters = [
136
136
  plugins = ["nonebot_plugin_parser"]
137
137
 
138
138
  [tool.poe.tasks]
139
- test_others = "pytest tests/others --cov=src --cov-report=xml --junitxml=junit.xml -n auto"
140
- test_parsers = "pytest tests/parsers --cov=src --cov-report=xml --junitxml=junit.xml -n auto"
141
- test_render = "pytest tests/render --cov=src --cov-report=xml --junitxml=junit.xml"
139
+ test-other = "pytest tests/others --cov=src --cov-report=xml --junitxml=junit.xml -n auto"
140
+ test-parser = "pytest tests/parsers --cov=src --cov-report=xml --junitxml=junit.xml -n auto"
141
+ test-render = "pytest tests/renders --cov=src --cov-report=xml --junitxml=junit.xml"
142
142
  bump = "bump-my-version bump"
143
143
  show-bump = "bump-my-version show-bump"
144
144
 
@@ -2,9 +2,8 @@ from enum import Enum
2
2
  from pathlib import Path
3
3
 
4
4
  from nonebot import require, get_driver, get_plugin_config
5
- from pilmoji import EmojiStyle
5
+ from apilmoji import ELK_SH_CDN, EmojiStyle
6
6
  from pydantic import BaseModel
7
- from pilmoji.source import ELK_SH_CDN
8
7
  from bilibili_api.video import VideoCodecs, VideoQuality
9
8
 
10
9
  from .constants import PlatformEnum
@@ -8,7 +8,7 @@ from typing_extensions import override
8
8
 
9
9
  from PIL import Image, ImageDraw, ImageFont
10
10
  from nonebot import logger
11
- from pilmoji import Pilmoji, EmojiCDNSource
11
+ from apilmoji import Apilmoji, EmojiCDNSource
12
12
 
13
13
  from .base import ParseResult, ImageRenderer
14
14
  from ..config import pconfig
@@ -298,14 +298,13 @@ class CommonRenderer(ImageRenderer):
298
298
  """默认字体路径"""
299
299
  DEFAULT_VIDEO_BUTTON_PATH: ClassVar[Path] = RESOURCES_DIR / _BUTTON_FILENAME
300
300
  """默认视频按钮路径"""
301
- PILMOJI: ClassVar[Pilmoji] = Pilmoji(
302
- source=EmojiCDNSource(
303
- base_url=pconfig.emoji_cdn,
304
- style=pconfig.emoji_style,
305
- cache_dir=pconfig.cache_dir / _EMOJIS,
306
- )
301
+ EMOJI_SOURCE: ClassVar[EmojiCDNSource] = EmojiCDNSource(
302
+ base_url=pconfig.emoji_cdn,
303
+ style=pconfig.emoji_style,
304
+ cache_dir=pconfig.cache_dir / _EMOJIS,
305
+ enable_tqdm=True,
307
306
  )
308
- """Pilmoji 实例"""
307
+ """Emoji Source"""
309
308
 
310
309
  @classmethod
311
310
  def load_resources(cls):
@@ -350,13 +349,22 @@ class CommonRenderer(ImageRenderer):
350
349
  async def text(
351
350
  cls,
352
351
  ctx: RenderContext,
353
- text: str,
354
352
  xy: tuple[int, int],
353
+ lines: list[str],
354
+ font: FontInfo,
355
355
  fill: Color,
356
- font: ImageFont.FreeTypeFont,
357
- ):
356
+ ) -> int:
358
357
  """绘制文本"""
359
- await cls.PILMOJI.text(ctx.image, xy, text, font, fill)
358
+ await Apilmoji.text(
359
+ ctx.image,
360
+ xy,
361
+ lines,
362
+ font.font,
363
+ fill=fill,
364
+ line_height=font.line_height,
365
+ source=cls.EMOJI_SOURCE,
366
+ )
367
+ return font.line_height * len(lines)
360
368
 
361
369
  @override
362
370
  async def render_image(self, result: ParseResult) -> bytes:
@@ -935,28 +943,24 @@ class CommonRenderer(ImageRenderer):
935
943
  text_y = text_start_y
936
944
 
937
945
  # 发布者名称(蓝色)
938
- for line in section.name_lines:
939
- await self.text(
940
- ctx,
941
- line,
942
- (text_x, text_y),
943
- self.HEADER_COLOR,
944
- self.fontset.name_font.font,
945
- )
946
- text_y += self.fontset.name_font.line_height
946
+ text_y += await self.text(
947
+ ctx,
948
+ (text_x, text_y),
949
+ section.name_lines,
950
+ self.fontset.name_font,
951
+ fill=self.HEADER_COLOR,
952
+ )
947
953
 
948
954
  # 时间(灰色)
949
955
  if section.time_lines:
950
956
  text_y += self.NAME_TIME_GAP
951
- for line in section.time_lines:
952
- await self.text(
953
- ctx,
954
- line,
955
- (text_x, text_y),
956
- self.EXTRA_COLOR,
957
- self.fontset.extra_font.font,
958
- )
959
- text_y += self.fontset.extra_font.line_height
957
+ text_y += await self.text(
958
+ ctx,
959
+ (text_x, text_y),
960
+ section.time_lines,
961
+ self.fontset.extra_font,
962
+ fill=self.EXTRA_COLOR,
963
+ )
960
964
 
961
965
  # 在右侧绘制平台 logo(仅在非转发内容时绘制)
962
966
  if ctx.not_repost:
@@ -973,15 +977,14 @@ class CommonRenderer(ImageRenderer):
973
977
 
974
978
  async def _draw_title(self, ctx: RenderContext, lines: list[str]) -> None:
975
979
  """绘制标题"""
976
- for line in lines:
977
- await self.text(
978
- ctx,
979
- line,
980
- (self.PADDING, ctx.y_pos),
981
- self.TEXT_COLOR,
982
- self.fontset.title_font.font,
983
- )
984
- ctx.y_pos += self.fontset.title_font.line_height
980
+ ctx.y_pos += await self.text(
981
+ ctx,
982
+ (self.PADDING, ctx.y_pos),
983
+ lines,
984
+ self.fontset.title_font,
985
+ self.TEXT_COLOR,
986
+ )
987
+
985
988
  ctx.y_pos += self.SECTION_SPACING
986
989
 
987
990
  def _draw_cover(self, ctx: RenderContext, cover_img: PILImage) -> None:
@@ -1004,30 +1007,26 @@ class CommonRenderer(ImageRenderer):
1004
1007
 
1005
1008
  async def _draw_text(self, ctx: RenderContext, lines: list[str]) -> None:
1006
1009
  """绘制文本内容"""
1007
- for line in lines:
1008
- await self.text(
1009
- ctx,
1010
- line,
1011
- (self.PADDING, ctx.y_pos),
1012
- self.TEXT_COLOR,
1013
- self.fontset.text_font.font,
1014
- )
1015
- ctx.y_pos += self.fontset.text_font.line_height
1010
+ ctx.y_pos += await self.text(
1011
+ ctx,
1012
+ (self.PADDING, ctx.y_pos),
1013
+ lines,
1014
+ self.fontset.text_font,
1015
+ fill=self.TEXT_COLOR,
1016
+ )
1016
1017
  ctx.y_pos += self.SECTION_SPACING
1017
1018
 
1018
1019
  async def _draw_graphics(self, ctx: RenderContext, section: GraphicsSectionData) -> None:
1019
1020
  """绘制图文内容"""
1020
1021
  # 绘制文本内容(如果有)
1021
1022
  if section.text_lines:
1022
- for line in section.text_lines:
1023
- await self.text(
1024
- ctx,
1025
- line,
1026
- (self.PADDING, ctx.y_pos),
1027
- self.TEXT_COLOR,
1028
- self.fontset.text_font.font,
1029
- )
1030
- ctx.y_pos += self.fontset.text_font.line_height
1023
+ ctx.y_pos += await self.text(
1024
+ ctx,
1025
+ (self.PADDING, ctx.y_pos),
1026
+ section.text_lines,
1027
+ self.fontset.text_font,
1028
+ fill=self.TEXT_COLOR,
1029
+ )
1031
1030
  ctx.y_pos += self.SECTION_SPACING # 文本和图片之间的间距
1032
1031
 
1033
1032
  # 绘制图片(居中)
@@ -1042,28 +1041,25 @@ class CommonRenderer(ImageRenderer):
1042
1041
  extra_font_info = self.fontset.extra_font
1043
1042
  text_width = extra_font_info.get_text_width(section.alt_text)
1044
1043
  text_x = self.PADDING + (ctx.content_width - text_width) // 2
1045
- await self.text(
1044
+ ctx.y_pos += await self.text(
1046
1045
  ctx,
1047
- section.alt_text,
1048
1046
  (text_x, ctx.y_pos),
1049
- self.EXTRA_COLOR,
1050
- extra_font_info.font,
1047
+ [section.alt_text],
1048
+ self.fontset.extra_font,
1049
+ fill=self.EXTRA_COLOR,
1051
1050
  )
1052
- ctx.y_pos += extra_font_info.line_height
1053
1051
 
1054
1052
  ctx.y_pos += self.SECTION_SPACING
1055
1053
 
1056
1054
  async def _draw_extra(self, ctx: RenderContext, lines: list[str]) -> None:
1057
1055
  """绘制额外信息"""
1058
- for line in lines:
1059
- await self.text(
1060
- ctx,
1061
- line,
1062
- (self.PADDING, ctx.y_pos),
1063
- self.EXTRA_COLOR,
1064
- self.fontset.extra_font.font,
1065
- )
1066
- ctx.y_pos += self.fontset.extra_font.line_height
1056
+ ctx.y_pos += await self.text(
1057
+ ctx,
1058
+ (self.PADDING, ctx.y_pos),
1059
+ lines,
1060
+ self.fontset.extra_font,
1061
+ fill=self.EXTRA_COLOR,
1062
+ )
1067
1063
 
1068
1064
  def _draw_repost(self, ctx: RenderContext, section: RepostSectionData) -> None:
1069
1065
  """绘制转发内容"""
@@ -1277,8 +1273,8 @@ class CommonRenderer(ImageRenderer):
1277
1273
  if not text:
1278
1274
  return []
1279
1275
 
1280
- lines = []
1281
- paragraphs = text.split("\n")
1276
+ lines: list[str] = []
1277
+ paragraphs = text.splitlines()
1282
1278
 
1283
1279
  def is_punctuation(char: str) -> bool:
1284
1280
  """判断是否为不能为行首的标点符号"""