|
1 | 1 | from asyncio import gather |
2 | 2 | from contextlib import asynccontextmanager |
| 3 | +from importlib.resources import as_file, files |
3 | 4 | from queue import PriorityQueue |
4 | 5 | from typing import Annotated, Any, AsyncGenerator |
5 | 6 |
|
|
11 | 12 | from nonebot.plugin import PluginMetadata |
12 | 13 | from nonebot_plugin_alconna import Alconna, Image, Subcommand, UniMessage, on_alconna |
13 | 14 | from nonebot_plugin_apscheduler import scheduler |
| 15 | +from nonebot_plugin_htmlkit import template_to_pic |
14 | 16 | from nonebot_plugin_htmlrender.browser import get_browser |
15 | 17 | from nonebot_plugin_orm import async_scoped_session, get_session |
16 | 18 | from nonebot_plugin_uninfo import MEMBER |
|
21 | 23 | from .....utils import run_task, send_message |
22 | 24 | from ... import plugin_config as bilibili_config |
23 | 25 | from ...utils import UID_ARG, get_share_click, handle_error, raise_for_status |
| 26 | +from . import templates |
24 | 27 | from .config import Config |
25 | 28 | from .models import Dynamic, Dynamics, Subscription |
26 | 29 |
|
|
45 | 48 | ) |
46 | 49 |
|
47 | 50 |
|
| 51 | +async def img_fetch_fn(url: str) -> bytes: |
| 52 | + return (await client.get(url + "@.avif")).content |
| 53 | + |
| 54 | + |
48 | 55 | class Cache: |
49 | 56 | data: set[str] |
50 | 57 | queue: PriorityQueue[str] |
@@ -82,7 +89,19 @@ async def get_dynamics(page: int = 1) -> Dynamics: |
82 | 89 | "type": "all", |
83 | 90 | "page": page, |
84 | 91 | "features": ",".join( |
85 | | - ("itemOpusStyle", "listOnlyfans", "opusBigCover", "onlyfansVote") |
| 92 | + ( |
| 93 | + "itemOpusStyle", |
| 94 | + "listOnlyfans", |
| 95 | + "opusBigCover", |
| 96 | + "onlyfansVote", |
| 97 | + "decorationCard", |
| 98 | + "onlyfansAssetsV2", |
| 99 | + "forwardListHidden", |
| 100 | + "ugcDelete", |
| 101 | + "onlyfansQaCard", |
| 102 | + "commentsNewVersion", |
| 103 | + "avatarAutoTheme", |
| 104 | + ) |
86 | 105 | ), |
87 | 106 | }, |
88 | 107 | ) |
@@ -163,7 +182,7 @@ async def render_screenshot(id_str: str) -> bytes: |
163 | 182 | ) |
164 | 183 | await page.add_style_tag( |
165 | 184 | content=""" |
166 | | - * { |
| 185 | + body { |
167 | 186 | font-family: "LXGW ZhenKai GB", "LXGW WenKai GB", sans-serif !important; |
168 | 187 | } |
169 | 188 |
|
@@ -198,15 +217,37 @@ async def render_screenshot(id_str: str) -> bytes: |
198 | 217 | async def broadcast(dynamics: list[Dynamic]): |
199 | 218 | async with get_session() as session: |
200 | 219 | for dynamic in dynamics: |
201 | | - screenshot, url, subs = await gather( |
202 | | - render_screenshot(dynamic["id_str"]), |
203 | | - get_share_click(dynamic["id_str"], "dynamic", "dt.dt-detail.0.0.pv"), |
204 | | - session.scalars( |
205 | | - select(Subscription).where( |
206 | | - Subscription.uid == dynamic["modules"]["module_author"]["mid"] |
207 | | - ) |
208 | | - ), |
209 | | - ) |
| 220 | + with as_file(files(templates)) as templates_path: |
| 221 | + screenshot, url, subs = await gather( |
| 222 | + ( |
| 223 | + template_to_pic( |
| 224 | + str(templates_path), |
| 225 | + "draw.html.j2", |
| 226 | + dynamic, |
| 227 | + max_width=360 * 3, |
| 228 | + device_height=640 * 3, |
| 229 | + img_fetch_fn=img_fetch_fn, |
| 230 | + allow_refit=False, |
| 231 | + image_format="jpeg", |
| 232 | + jpeg_quality=80, |
| 233 | + ) |
| 234 | + if dynamic["type"] == "DYNAMIC_TYPE_WORD" |
| 235 | + or ( |
| 236 | + dynamic["type"] == "DYNAMIC_TYPE_DRAW" |
| 237 | + and not dynamic["modules"]["module_dynamic"]["additional"] |
| 238 | + ) |
| 239 | + else render_screenshot(dynamic["id_str"]) |
| 240 | + ), |
| 241 | + get_share_click( |
| 242 | + dynamic["id_str"], "dynamic", "dt.dt-detail.0.0.pv" |
| 243 | + ), |
| 244 | + session.scalars( |
| 245 | + select(Subscription).where( |
| 246 | + Subscription.uid |
| 247 | + == dynamic["modules"]["module_author"]["mid"] |
| 248 | + ) |
| 249 | + ), |
| 250 | + ) |
210 | 251 |
|
211 | 252 | msg = plugin_config.template.format( |
212 | 253 | name=dynamic["modules"]["module_author"]["name"], |
@@ -310,16 +351,52 @@ async def _(id_str: str): |
310 | 351 | dynamic = raise_for_status( |
311 | 352 | await client.get( |
312 | 353 | "/polymer/web-dynamic/v1/detail", |
313 | | - params={"id": id_str, "features": "itemOpusStyle"}, |
| 354 | + params={ |
| 355 | + "id": id_str, |
| 356 | + "features": ",".join( |
| 357 | + ( |
| 358 | + "itemOpusStyle", |
| 359 | + "listOnlyfans", |
| 360 | + "opusBigCover", |
| 361 | + "onlyfansVote", |
| 362 | + "decorationCard", |
| 363 | + "onlyfansAssetsV2", |
| 364 | + "forwardListHidden", |
| 365 | + "ugcDelete", |
| 366 | + "onlyfansQaCard", |
| 367 | + "commentsNewVersion", |
| 368 | + "avatarAutoTheme", |
| 369 | + ) |
| 370 | + ), |
| 371 | + }, |
314 | 372 | ) |
315 | 373 | )["item"] |
316 | 374 | except Exception: |
317 | 375 | await handle_error("获取动态信息失败") |
318 | 376 |
|
319 | | - screenshot, url = await gather( |
320 | | - render_screenshot(id_str), |
321 | | - get_share_click(id_str, "dynamic", "dt.dt-detail.0.0.pv"), |
322 | | - ) |
| 377 | + with as_file(files(templates)) as templates_path: |
| 378 | + screenshot, url = await gather( |
| 379 | + ( |
| 380 | + template_to_pic( |
| 381 | + str(templates_path), |
| 382 | + "draw.html.j2", |
| 383 | + dynamic, |
| 384 | + max_width=360 * 3, |
| 385 | + device_height=640 * 3, |
| 386 | + img_fetch_fn=img_fetch_fn, |
| 387 | + allow_refit=False, |
| 388 | + image_format="jpeg", |
| 389 | + jpeg_quality=80, |
| 390 | + ) |
| 391 | + if dynamic["type"] == "DYNAMIC_TYPE_WORD" |
| 392 | + or ( |
| 393 | + dynamic["type"] == "DYNAMIC_TYPE_DRAW" |
| 394 | + and not dynamic["modules"]["module_dynamic"]["additional"] |
| 395 | + ) |
| 396 | + else render_screenshot(dynamic["id_str"]) |
| 397 | + ), |
| 398 | + get_share_click(id_str, "dynamic", "dt.dt-detail.0.0.pv"), |
| 399 | + ) |
323 | 400 | await plugin_config.template.format( |
324 | 401 | name=dynamic["modules"]["module_author"]["name"], |
325 | 402 | action=dynamic["modules"]["module_author"]["pub_action"] |
|
0 commit comments