nonebot-plugin-htmlrender 0.7.0a3__py3-none-any.whl → 0.7.2__py3-none-any.whl
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.
- nonebot_plugin_htmlrender/__init__.py +146 -22
- nonebot_plugin_htmlrender/_bootstrap.py +122 -0
- nonebot_plugin_htmlrender/_compat.py +308 -0
- nonebot_plugin_htmlrender/backend/__init__.py +39 -0
- nonebot_plugin_htmlrender/backend/base.py +217 -0
- nonebot_plugin_htmlrender/backend/factory.py +222 -0
- nonebot_plugin_htmlrender/backend/playwright/__init__.py +9 -0
- nonebot_plugin_htmlrender/backend/playwright/_page.py +258 -0
- nonebot_plugin_htmlrender/backend/playwright/config.py +244 -0
- nonebot_plugin_htmlrender/backend/playwright/data_source.py +90 -0
- nonebot_plugin_htmlrender/backend/playwright/install.py +161 -0
- nonebot_plugin_htmlrender/backend/playwright/models.py +432 -0
- nonebot_plugin_htmlrender/backend/playwright/operations.py +707 -0
- nonebot_plugin_htmlrender/backend/playwright/render.py +772 -0
- nonebot_plugin_htmlrender/backend/playwright/runtime.py +441 -0
- nonebot_plugin_htmlrender/backend/playwright/telemetry.py +240 -0
- nonebot_plugin_htmlrender/backend/playwright/types.py +280 -0
- nonebot_plugin_htmlrender/browser.py +31 -290
- nonebot_plugin_htmlrender/config.py +35 -86
- nonebot_plugin_htmlrender/consts.py +109 -23
- nonebot_plugin_htmlrender/data_source.py +36 -312
- nonebot_plugin_htmlrender/py.typed +0 -0
- nonebot_plugin_htmlrender/render.py +720 -0
- nonebot_plugin_htmlrender/resources/__init__.py +34 -0
- nonebot_plugin_htmlrender/resources/config.py +66 -0
- nonebot_plugin_htmlrender/resources/filehost/__init__.py +162 -0
- nonebot_plugin_htmlrender/resources/filehost/cache.py +258 -0
- nonebot_plugin_htmlrender/resources/filehost/guard.py +159 -0
- nonebot_plugin_htmlrender/resources/filehost/warmup.py +256 -0
- nonebot_plugin_htmlrender/resources/resolve.py +348 -0
- nonebot_plugin_htmlrender/resources/template.py +313 -0
- nonebot_plugin_htmlrender/templates/{markdown.html → markdown/markdown.html} +3 -3
- nonebot_plugin_htmlrender/templates/{text.html → text/text.html} +1 -1
- nonebot_plugin_htmlrender/utils/__init__.py +48 -0
- nonebot_plugin_htmlrender/utils/install.py +172 -0
- nonebot_plugin_htmlrender/utils/process.py +292 -0
- nonebot_plugin_htmlrender/utils/signal.py +165 -0
- nonebot_plugin_htmlrender/utils/telemetry/__init__.py +91 -0
- nonebot_plugin_htmlrender/utils/telemetry/common.py +160 -0
- nonebot_plugin_htmlrender/utils/telemetry/prometheus.py +199 -0
- nonebot_plugin_htmlrender/utils/telemetry/sentry.py +228 -0
- nonebot_plugin_htmlrender-0.7.2.dist-info/METADATA +205 -0
- nonebot_plugin_htmlrender-0.7.2.dist-info/RECORD +52 -0
- {nonebot_plugin_htmlrender-0.7.0a3.dist-info → nonebot_plugin_htmlrender-0.7.2.dist-info}/WHEEL +1 -1
- nonebot_plugin_htmlrender/install.py +0 -251
- nonebot_plugin_htmlrender/process.py +0 -193
- nonebot_plugin_htmlrender/signal.py +0 -138
- nonebot_plugin_htmlrender/utils.py +0 -222
- nonebot_plugin_htmlrender-0.7.0a3.dist-info/METADATA +0 -222
- nonebot_plugin_htmlrender-0.7.0a3.dist-info/RECORD +0 -22
- /nonebot_plugin_htmlrender/templates/{github-markdown-light.css → markdown/github-markdown-light.css} +0 -0
- /nonebot_plugin_htmlrender/templates/{katex → markdown/katex}/katex.min.b64_fonts.css +0 -0
- /nonebot_plugin_htmlrender/templates/{katex → markdown/katex}/katex.min.js +0 -0
- /nonebot_plugin_htmlrender/templates/{katex → markdown/katex}/mathtex-script-type.min.js +0 -0
- /nonebot_plugin_htmlrender/templates/{katex → markdown/katex}/mhchem.min.js +0 -0
- /nonebot_plugin_htmlrender/templates/{pygments-default.css → markdown/pygments-default.css} +0 -0
- /nonebot_plugin_htmlrender/templates/{text.css → text/text.css} +0 -0
- {nonebot_plugin_htmlrender-0.7.0a3.dist-info → nonebot_plugin_htmlrender-0.7.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,64 +1,188 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
1
4
|
import nonebot
|
|
2
5
|
from nonebot import require
|
|
3
|
-
|
|
4
|
-
require("nonebot_plugin_localstore")
|
|
5
6
|
from nonebot.log import logger
|
|
6
7
|
from nonebot.plugin import PluginMetadata
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
require("nonebot_plugin_localstore")
|
|
10
|
+
|
|
11
|
+
from nonebot_plugin_htmlrender._bootstrap import (
|
|
12
|
+
_bootstrap_filehost_guard_on_import as _bootstrap_filehost_guard_on_import,
|
|
13
|
+
)
|
|
14
|
+
from nonebot_plugin_htmlrender._bootstrap import (
|
|
15
|
+
_bootstrap_optional_plugins_on_import as _bootstrap_optional_plugins_on_import,
|
|
16
|
+
)
|
|
17
|
+
from nonebot_plugin_htmlrender._bootstrap import (
|
|
18
|
+
_patch_filehost_request_headers_validator as _patch_filehost_request_headers_validator,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
_bootstrap_optional_plugins_on_import()
|
|
22
|
+
_bootstrap_filehost_guard_on_import()
|
|
23
|
+
|
|
24
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
25
|
+
capture_element as capture_element,
|
|
26
|
+
)
|
|
27
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
28
|
+
get_new_page as get_new_page,
|
|
29
|
+
)
|
|
30
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
31
|
+
html_to_pic as html_to_pic,
|
|
32
|
+
)
|
|
33
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
34
|
+
md_to_pic as md_to_pic,
|
|
12
35
|
)
|
|
36
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
37
|
+
shutdown_htmlrender as shutdown_htmlrender,
|
|
38
|
+
)
|
|
39
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
40
|
+
startup_htmlrender as startup_htmlrender,
|
|
41
|
+
)
|
|
42
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
43
|
+
template_to_html as template_to_html,
|
|
44
|
+
)
|
|
45
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
46
|
+
template_to_pic as template_to_pic,
|
|
47
|
+
)
|
|
48
|
+
from nonebot_plugin_htmlrender._compat import (
|
|
49
|
+
text_to_pic as text_to_pic,
|
|
50
|
+
)
|
|
51
|
+
from nonebot_plugin_htmlrender.backend.factory import ensure_backend_loaded
|
|
13
52
|
from nonebot_plugin_htmlrender.config import Config, plugin_config
|
|
14
|
-
from nonebot_plugin_htmlrender.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
53
|
+
from nonebot_plugin_htmlrender.consts import RenderBackend, RenderStartupMode
|
|
54
|
+
from nonebot_plugin_htmlrender.render import (
|
|
55
|
+
available_render_backends,
|
|
56
|
+
capture_html_element,
|
|
57
|
+
get_default_render,
|
|
58
|
+
get_render,
|
|
59
|
+
get_render_backend_status,
|
|
60
|
+
get_render_context,
|
|
61
|
+
is_render_backend_available,
|
|
62
|
+
is_render_backend_registered,
|
|
63
|
+
list_render_backend_statuses,
|
|
64
|
+
probe_render,
|
|
65
|
+
registered_render_backends,
|
|
66
|
+
render_html,
|
|
67
|
+
render_markdown,
|
|
68
|
+
render_template,
|
|
69
|
+
render_template_html,
|
|
70
|
+
render_text,
|
|
71
|
+
shutdown_render,
|
|
72
|
+
startup_render,
|
|
73
|
+
unavailable_render_backends,
|
|
74
|
+
)
|
|
75
|
+
from nonebot_plugin_htmlrender.resources import (
|
|
76
|
+
ResourceResolveError,
|
|
77
|
+
resolve_template_vars,
|
|
78
|
+
to_resource_url,
|
|
21
79
|
)
|
|
22
|
-
from nonebot_plugin_htmlrender.utils import _clear_playwright_env_vars
|
|
23
80
|
|
|
24
81
|
__plugin_meta__ = PluginMetadata(
|
|
25
82
|
name="nonebot-plugin-htmlrender",
|
|
26
83
|
description="通过浏览器渲染图片",
|
|
27
|
-
usage=
|
|
84
|
+
usage=(
|
|
85
|
+
"提供 HTML/Markdown/模板渲染为图片的能力,作为库插件供其他插件调用。\n"
|
|
86
|
+
"主要接口:render_html, render_text, render_markdown, render_template 等。"
|
|
87
|
+
),
|
|
28
88
|
type="library",
|
|
29
89
|
config=Config,
|
|
30
90
|
homepage="https://github.com/kexue-z/nonebot-plugin-htmlrender",
|
|
31
|
-
|
|
91
|
+
supported_adapters=None,
|
|
32
92
|
)
|
|
33
93
|
|
|
34
94
|
driver = nonebot.get_driver()
|
|
35
95
|
|
|
36
96
|
|
|
97
|
+
def _prepare_playwright_startup() -> None:
|
|
98
|
+
ensure_backend_loaded(RenderBackend.PLAYWRIGHT)
|
|
99
|
+
page_module = import_module("nonebot_plugin_htmlrender.backend.playwright._page")
|
|
100
|
+
register_render_context_provider = page_module.register_render_context_provider
|
|
101
|
+
register_render_context_provider(get_render_context)
|
|
102
|
+
|
|
103
|
+
|
|
37
104
|
@driver.on_startup
|
|
38
|
-
async def init(**kwargs):
|
|
105
|
+
async def init(**kwargs: Any) -> None:
|
|
106
|
+
"""插件启动时初始化渲染后端。"""
|
|
39
107
|
logger.info("HTMLRender Starting...")
|
|
40
|
-
|
|
108
|
+
if plugin_config.render_backend is None:
|
|
109
|
+
logger.info("No render backend selected; startup skipped.")
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
startup_mode = plugin_config.render_startup_mode
|
|
114
|
+
if startup_mode == RenderStartupMode.OFF:
|
|
115
|
+
logger.info("Render startup skipped by configuration.")
|
|
116
|
+
return
|
|
117
|
+
if plugin_config.render_backend == RenderBackend.PLAYWRIGHT:
|
|
118
|
+
filehost_module = import_module(
|
|
119
|
+
"nonebot_plugin_htmlrender.resources.filehost"
|
|
120
|
+
)
|
|
121
|
+
ensure_filehost_runtime_ready = (
|
|
122
|
+
filehost_module.ensure_filehost_runtime_ready
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
_prepare_playwright_startup()
|
|
126
|
+
await ensure_filehost_runtime_ready(reason="plugin_startup")
|
|
127
|
+
if startup_mode == RenderStartupMode.WARMUP:
|
|
128
|
+
await startup_render(**kwargs)
|
|
129
|
+
else:
|
|
130
|
+
await startup_render(**kwargs)
|
|
131
|
+
await probe_render()
|
|
132
|
+
except Exception as e:
|
|
133
|
+
logger.exception("Failed to start render runtime.")
|
|
134
|
+
raise RuntimeError("Render runtime startup failed.") from e
|
|
135
|
+
|
|
41
136
|
logger.opt(colors=True).info(
|
|
42
|
-
f"HTMLRender Started with <cyan>{plugin_config.
|
|
137
|
+
f"HTMLRender Started with backend <cyan>{plugin_config.render_backend}</cyan>."
|
|
43
138
|
)
|
|
44
139
|
|
|
45
140
|
|
|
46
141
|
@driver.on_shutdown
|
|
47
|
-
async def shutdown():
|
|
142
|
+
async def shutdown() -> None:
|
|
143
|
+
"""插件关闭时清理渲染资源。"""
|
|
48
144
|
logger.info("HTMLRender Shutting down...")
|
|
49
|
-
await
|
|
50
|
-
|
|
145
|
+
await shutdown_render()
|
|
146
|
+
if plugin_config.render_backend == RenderBackend.PLAYWRIGHT:
|
|
147
|
+
runtime_module = import_module(
|
|
148
|
+
"nonebot_plugin_htmlrender.backend.playwright.runtime"
|
|
149
|
+
)
|
|
150
|
+
clear_playwright_env_vars = runtime_module.clear_playwright_env_vars
|
|
151
|
+
|
|
152
|
+
clear_playwright_env_vars()
|
|
51
153
|
logger.info("HTMLRender Shut down.")
|
|
52
154
|
|
|
53
155
|
|
|
54
156
|
__all__ = [
|
|
157
|
+
"ResourceResolveError",
|
|
158
|
+
"available_render_backends",
|
|
55
159
|
"capture_element",
|
|
160
|
+
"capture_html_element",
|
|
161
|
+
"get_default_render",
|
|
56
162
|
"get_new_page",
|
|
163
|
+
"get_render",
|
|
164
|
+
"get_render_backend_status",
|
|
165
|
+
"get_render_context",
|
|
57
166
|
"html_to_pic",
|
|
167
|
+
"is_render_backend_available",
|
|
168
|
+
"is_render_backend_registered",
|
|
169
|
+
"list_render_backend_statuses",
|
|
58
170
|
"md_to_pic",
|
|
171
|
+
"probe_render",
|
|
172
|
+
"registered_render_backends",
|
|
173
|
+
"render_html",
|
|
174
|
+
"render_markdown",
|
|
175
|
+
"render_template",
|
|
176
|
+
"render_template_html",
|
|
177
|
+
"render_text",
|
|
178
|
+
"resolve_template_vars",
|
|
59
179
|
"shutdown_htmlrender",
|
|
180
|
+
"shutdown_render",
|
|
60
181
|
"startup_htmlrender",
|
|
182
|
+
"startup_render",
|
|
61
183
|
"template_to_html",
|
|
62
184
|
"template_to_pic",
|
|
63
185
|
"text_to_pic",
|
|
186
|
+
"to_resource_url",
|
|
187
|
+
"unavailable_render_backends",
|
|
64
188
|
]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Bootstrap helpers executed at plugin import time."""
|
|
2
|
+
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from importlib.util import find_spec
|
|
5
|
+
|
|
6
|
+
from nonebot import require
|
|
7
|
+
from nonebot.log import logger
|
|
8
|
+
|
|
9
|
+
from nonebot_plugin_htmlrender.config import plugin_config
|
|
10
|
+
from nonebot_plugin_htmlrender.consts import (
|
|
11
|
+
LocalLocalResourcePolicy,
|
|
12
|
+
RemoteLocalResourcePolicy,
|
|
13
|
+
RenderBackend,
|
|
14
|
+
ResourceResolveMode,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
_OPTIONAL_PLUGIN_IDS = (
|
|
18
|
+
"nonebot_plugin_sentry",
|
|
19
|
+
"nonebot_plugin_prometheus",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _enum_value(raw: object) -> str:
|
|
24
|
+
"""Return the string value for enum-like configuration entries."""
|
|
25
|
+
return getattr(raw, "value", str(raw))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _playwright_filehost_policy_enabled() -> bool:
|
|
29
|
+
"""Check whether Playwright config explicitly needs filehost bootstrap."""
|
|
30
|
+
try:
|
|
31
|
+
config_module = import_module(
|
|
32
|
+
"nonebot_plugin_htmlrender.backend.playwright.config"
|
|
33
|
+
)
|
|
34
|
+
get_playwright_config = config_module.get_playwright_config
|
|
35
|
+
cfg = get_playwright_config()
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.warning(f"Skipping filehost import bootstrap: invalid config: {e}")
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
if _enum_value(cfg.resource_resolve_mode) == ResourceResolveMode.OFF.value:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
_enum_value(cfg.remote_local_resource_policy)
|
|
45
|
+
== RemoteLocalResourcePolicy.FILEHOST.value
|
|
46
|
+
or _enum_value(cfg.local_local_resource_policy)
|
|
47
|
+
== LocalLocalResourcePolicy.FILEHOST.value
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _patch_filehost_request_headers_validator() -> None:
|
|
52
|
+
"""修补 filehost 请求头验证器以兼容 pydantic。"""
|
|
53
|
+
try:
|
|
54
|
+
# TODO: Open an upstream issue for nonebot-plugin-filehost to replace
|
|
55
|
+
# __get_validators__ with __get_pydantic_core_schema__.
|
|
56
|
+
filehost_models = import_module("nonebot_plugin_filehost.models")
|
|
57
|
+
request_headers = getattr(filehost_models, "RequestHeaders", None)
|
|
58
|
+
request_scope_info = getattr(filehost_models, "RequestScopeInfo", None)
|
|
59
|
+
if request_headers is None or request_scope_info is None:
|
|
60
|
+
return
|
|
61
|
+
if bool(getattr(request_headers, "__htmlrender_validator_patched__", False)):
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
raw_validate = request_headers.__dict__.get("validate")
|
|
65
|
+
if not isinstance(raw_validate, classmethod):
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
validate_func = raw_validate.__func__
|
|
69
|
+
|
|
70
|
+
def _compat_validate(cls, value, *args, **kwargs): # type: ignore[no-untyped-def]
|
|
71
|
+
"""兼容性验证包装器。"""
|
|
72
|
+
del args, kwargs
|
|
73
|
+
return validate_func(cls, value)
|
|
74
|
+
|
|
75
|
+
request_headers.validate = classmethod(_compat_validate)
|
|
76
|
+
request_headers.__htmlrender_validator_patched__ = True
|
|
77
|
+
model_rebuild = getattr(request_scope_info, "model_rebuild", None)
|
|
78
|
+
if callable(model_rebuild):
|
|
79
|
+
model_rebuild(force=True)
|
|
80
|
+
logger.opt(colors=True).info(
|
|
81
|
+
"Patched <c>nonebot_plugin_filehost</c> websocket scope validator for pydantic compatibility."
|
|
82
|
+
)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.opt(colors=True).warning(
|
|
85
|
+
"Failed to patch <c>nonebot_plugin_filehost</c> validator compatibility: <r>{e}</r>",
|
|
86
|
+
e=e,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _bootstrap_optional_plugins_on_import() -> None:
|
|
91
|
+
"""在导入时引导可选插件。"""
|
|
92
|
+
for plugin_name in _OPTIONAL_PLUGIN_IDS:
|
|
93
|
+
if find_spec(plugin_name) is None:
|
|
94
|
+
logger.opt(colors=True).info(
|
|
95
|
+
"Optional plugin <d>{plugin_name}</d> not installed, skip bootstrap.",
|
|
96
|
+
plugin_name=plugin_name,
|
|
97
|
+
)
|
|
98
|
+
continue
|
|
99
|
+
require(plugin_name)
|
|
100
|
+
logger.opt(colors=True).info(
|
|
101
|
+
"Optional plugin <c>{plugin_name}</c> bootstrapped on import.",
|
|
102
|
+
plugin_name=plugin_name,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _bootstrap_filehost_guard_on_import() -> None:
|
|
107
|
+
"""在导入时安装 filehost 请求守卫。"""
|
|
108
|
+
|
|
109
|
+
if plugin_config.render_backend != RenderBackend.PLAYWRIGHT:
|
|
110
|
+
return
|
|
111
|
+
if not _playwright_filehost_policy_enabled():
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
filehost_module = import_module("nonebot_plugin_htmlrender.resources.filehost")
|
|
115
|
+
ensure_filehost_plugin_loaded = filehost_module.ensure_filehost_plugin_loaded
|
|
116
|
+
ensure_filehost_request_guard_installed = (
|
|
117
|
+
filehost_module.ensure_filehost_request_guard_installed
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if not ensure_filehost_plugin_loaded(reason="plugin_import"):
|
|
121
|
+
return
|
|
122
|
+
ensure_filehost_request_guard_installed(reason="plugin_import")
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# ruff: noqa: A002, FBT001, FBT002, PTH109
|
|
2
|
+
"""Backward-compatible deprecated API surface.
|
|
3
|
+
|
|
4
|
+
All deprecated top-level functions are defined here. Other modules
|
|
5
|
+
(``data_source``, ``browser``, ``__init__``) re-export from this
|
|
6
|
+
module so that old import paths keep working.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from contextlib import asynccontextmanager
|
|
12
|
+
from importlib import import_module
|
|
13
|
+
from os import getcwd
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
15
|
+
from typing_extensions import deprecated
|
|
16
|
+
|
|
17
|
+
from nonebot_plugin_htmlrender.render import (
|
|
18
|
+
capture_html_element,
|
|
19
|
+
get_render,
|
|
20
|
+
get_render_context,
|
|
21
|
+
render_html,
|
|
22
|
+
render_markdown,
|
|
23
|
+
render_template,
|
|
24
|
+
render_template_html,
|
|
25
|
+
render_text,
|
|
26
|
+
shutdown_render,
|
|
27
|
+
startup_render,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from collections.abc import AsyncIterator
|
|
32
|
+
from typing_extensions import Unpack
|
|
33
|
+
|
|
34
|
+
from playwright.async_api import Browser
|
|
35
|
+
|
|
36
|
+
from nonebot_plugin_htmlrender.backend.playwright.types import (
|
|
37
|
+
BrowserSessionKwargs,
|
|
38
|
+
GotoKwargs,
|
|
39
|
+
HtmlPageKwargs,
|
|
40
|
+
LocatorScreenshotKwargs,
|
|
41
|
+
PageContextKwargs,
|
|
42
|
+
TemplatePageKwargs,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def read_file(path: str) -> str:
|
|
47
|
+
operations = import_module(
|
|
48
|
+
"nonebot_plugin_htmlrender.backend.playwright.operations"
|
|
49
|
+
)
|
|
50
|
+
read_file_fn = operations.read_file
|
|
51
|
+
|
|
52
|
+
return await read_file_fn(path)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def read_tpl(path: str) -> str:
|
|
56
|
+
operations = import_module(
|
|
57
|
+
"nonebot_plugin_htmlrender.backend.playwright.operations"
|
|
58
|
+
)
|
|
59
|
+
read_tpl_fn = operations.read_tpl
|
|
60
|
+
|
|
61
|
+
return await read_tpl_fn(path)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _require_browser(session: object) -> Browser:
|
|
65
|
+
"""从渲染会话中提取 Browser 实例。
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
session: 渲染会话对象,需包含 ``handle`` 属性。
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
会话中的 :class:`Browser` 实例。
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
RuntimeError: 当前渲染目标不是 Browser 实例时抛出。
|
|
75
|
+
"""
|
|
76
|
+
playwright_api = import_module("playwright.async_api")
|
|
77
|
+
browser_type = playwright_api.Browser
|
|
78
|
+
|
|
79
|
+
browser = getattr(session, "handle", None)
|
|
80
|
+
if isinstance(browser, browser_type):
|
|
81
|
+
return cast("Browser", browser)
|
|
82
|
+
raise RuntimeError("Current render target is not a Browser instance.")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@deprecated("`text_to_pic` is deprecated. Use `render_text` instead.")
|
|
86
|
+
async def text_to_pic(
|
|
87
|
+
text: str,
|
|
88
|
+
css_path: str = "",
|
|
89
|
+
width: int = 500,
|
|
90
|
+
type: Literal["jpeg", "png"] = "png",
|
|
91
|
+
quality: int | None = None,
|
|
92
|
+
device_scale_factor: float = 2,
|
|
93
|
+
screenshot_timeout: float | None = 30_000,
|
|
94
|
+
) -> bytes:
|
|
95
|
+
"""已弃用:将文本渲染为图片,请使用 ``render_text``。"""
|
|
96
|
+
return await render_text(
|
|
97
|
+
text,
|
|
98
|
+
css_path=css_path,
|
|
99
|
+
width=width,
|
|
100
|
+
image_type=type,
|
|
101
|
+
quality=quality,
|
|
102
|
+
device_scale_factor=device_scale_factor,
|
|
103
|
+
screenshot_timeout=screenshot_timeout,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@deprecated("`md_to_pic` is deprecated. Use `render_markdown` instead.")
|
|
108
|
+
async def md_to_pic(
|
|
109
|
+
md: str = "",
|
|
110
|
+
md_path: str = "",
|
|
111
|
+
css_path: str = "",
|
|
112
|
+
width: int = 500,
|
|
113
|
+
type: Literal["jpeg", "png"] = "png",
|
|
114
|
+
quality: int | None = None,
|
|
115
|
+
device_scale_factor: float = 2,
|
|
116
|
+
screenshot_timeout: float | None = 30_000,
|
|
117
|
+
) -> bytes:
|
|
118
|
+
"""已弃用:将 Markdown 渲染为图片,请使用 ``render_markdown``。"""
|
|
119
|
+
return await render_markdown(
|
|
120
|
+
md,
|
|
121
|
+
md_path=md_path,
|
|
122
|
+
css_path=css_path,
|
|
123
|
+
width=width,
|
|
124
|
+
image_type=type,
|
|
125
|
+
quality=quality,
|
|
126
|
+
device_scale_factor=device_scale_factor,
|
|
127
|
+
screenshot_timeout=screenshot_timeout,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@deprecated("`template_to_html` is deprecated. Use `render_template_html` instead.")
|
|
132
|
+
async def template_to_html(
|
|
133
|
+
template_path: str,
|
|
134
|
+
template_name: str,
|
|
135
|
+
filters: dict[str, Any] | None = None,
|
|
136
|
+
**kwargs: Any,
|
|
137
|
+
) -> str:
|
|
138
|
+
"""已弃用:将模板渲染为 HTML,请使用 ``render_template_html``。"""
|
|
139
|
+
return await render_template_html(
|
|
140
|
+
template_path,
|
|
141
|
+
template_name=template_name,
|
|
142
|
+
filters=filters,
|
|
143
|
+
**kwargs,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@deprecated("`html_to_pic` is deprecated. Use `render_html` instead.")
|
|
148
|
+
async def html_to_pic(
|
|
149
|
+
html: str,
|
|
150
|
+
wait: int = 0,
|
|
151
|
+
template_path: str | None = None,
|
|
152
|
+
type: Literal["jpeg", "png"] = "png",
|
|
153
|
+
quality: int | None = None,
|
|
154
|
+
device_scale_factor: float = 2,
|
|
155
|
+
screenshot_timeout: float | None = 30_000,
|
|
156
|
+
full_page: bool = True,
|
|
157
|
+
**kwargs: Unpack[HtmlPageKwargs],
|
|
158
|
+
) -> bytes:
|
|
159
|
+
"""已弃用:将 HTML 渲染为图片,请使用 ``render_html``。"""
|
|
160
|
+
return await render_html(
|
|
161
|
+
html,
|
|
162
|
+
wait=wait,
|
|
163
|
+
template_path=template_path,
|
|
164
|
+
image_type=type,
|
|
165
|
+
quality=quality,
|
|
166
|
+
device_scale_factor=device_scale_factor,
|
|
167
|
+
screenshot_timeout=screenshot_timeout,
|
|
168
|
+
full_page=full_page,
|
|
169
|
+
**kwargs,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@deprecated("`template_to_pic` is deprecated. Use `render_template` instead.")
|
|
174
|
+
async def template_to_pic(
|
|
175
|
+
template_path: str,
|
|
176
|
+
template_name: str,
|
|
177
|
+
templates: dict[str, Any],
|
|
178
|
+
filters: dict[str, Any] | None = None,
|
|
179
|
+
pages: TemplatePageKwargs | None = None,
|
|
180
|
+
wait: int = 0,
|
|
181
|
+
type: Literal["jpeg", "png"] = "png",
|
|
182
|
+
quality: int | None = None,
|
|
183
|
+
device_scale_factor: float = 2,
|
|
184
|
+
screenshot_timeout: float | None = 30_000,
|
|
185
|
+
) -> bytes:
|
|
186
|
+
"""已弃用:将模板渲染为图片,请使用 ``render_template``。"""
|
|
187
|
+
default_pages: TemplatePageKwargs = {
|
|
188
|
+
"viewport": {"width": 500, "height": 10},
|
|
189
|
+
"base_url": f"file://{getcwd()}",
|
|
190
|
+
}
|
|
191
|
+
return await render_template(
|
|
192
|
+
template_path,
|
|
193
|
+
template_name=template_name,
|
|
194
|
+
templates=templates,
|
|
195
|
+
filters=filters,
|
|
196
|
+
pages=pages or default_pages,
|
|
197
|
+
wait=wait,
|
|
198
|
+
image_type=type,
|
|
199
|
+
quality=quality,
|
|
200
|
+
device_scale_factor=device_scale_factor,
|
|
201
|
+
screenshot_timeout=screenshot_timeout,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@deprecated("`capture_element` is deprecated. Use `capture_html_element` instead.")
|
|
206
|
+
async def capture_element(
|
|
207
|
+
url: str,
|
|
208
|
+
element: str,
|
|
209
|
+
page_kwargs: PageContextKwargs | None = None,
|
|
210
|
+
goto_kwargs: GotoKwargs | None = None,
|
|
211
|
+
screenshot_kwargs: LocatorScreenshotKwargs | None = None,
|
|
212
|
+
) -> bytes:
|
|
213
|
+
"""已弃用:捕获页面元素截图,请使用 ``capture_html_element``。"""
|
|
214
|
+
return await capture_html_element(
|
|
215
|
+
url,
|
|
216
|
+
element,
|
|
217
|
+
page_kwargs=page_kwargs,
|
|
218
|
+
goto_kwargs=goto_kwargs,
|
|
219
|
+
screenshot_kwargs=screenshot_kwargs,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@deprecated("`get_new_page` is deprecated. Use `get_render_context` instead.")
|
|
224
|
+
@asynccontextmanager
|
|
225
|
+
async def get_new_page(
|
|
226
|
+
device_scale_factor: float = 2,
|
|
227
|
+
**kwargs: Unpack[HtmlPageKwargs],
|
|
228
|
+
) -> AsyncIterator[object]:
|
|
229
|
+
"""已弃用:获取新的浏览器页面,请使用 ``get_render_context``。"""
|
|
230
|
+
async with get_render_context(
|
|
231
|
+
device_scale_factor=device_scale_factor,
|
|
232
|
+
**kwargs,
|
|
233
|
+
) as page:
|
|
234
|
+
yield page
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
@deprecated("`get_browser` is deprecated. Use `get_render` instead.")
|
|
238
|
+
async def get_browser(**kwargs: Unpack[BrowserSessionKwargs]) -> Browser:
|
|
239
|
+
"""已弃用:获取浏览器实例,请使用 ``get_render``。"""
|
|
240
|
+
session = await get_render(**kwargs)
|
|
241
|
+
return _require_browser(session)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@deprecated("`startup_htmlrender` is deprecated. Use `startup_render` instead.")
|
|
245
|
+
async def startup_htmlrender(**kwargs: Unpack[BrowserSessionKwargs]) -> Browser:
|
|
246
|
+
"""已弃用:启动 HTML 渲染引擎,请使用 ``startup_render``。"""
|
|
247
|
+
session = await startup_render(**kwargs)
|
|
248
|
+
return _require_browser(session)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@deprecated("`shutdown_htmlrender` is deprecated. Use `shutdown_render` instead.")
|
|
252
|
+
async def shutdown_htmlrender() -> None:
|
|
253
|
+
"""已弃用:关闭 HTML 渲染引擎,请使用 ``shutdown_render``。"""
|
|
254
|
+
await shutdown_render()
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@deprecated("`_launch` is deprecated. Use `startup_render` instead.")
|
|
258
|
+
async def _launch(
|
|
259
|
+
browser_type: str,
|
|
260
|
+
**kwargs: Unpack[BrowserSessionKwargs],
|
|
261
|
+
) -> Browser:
|
|
262
|
+
"""已弃用:启动浏览器,请使用 ``startup_render``。"""
|
|
263
|
+
_ = browser_type
|
|
264
|
+
return await startup_htmlrender(**kwargs)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@deprecated(
|
|
268
|
+
"`clean_playwright_cache` from `nonebot_plugin_htmlrender.browser` is deprecated. "
|
|
269
|
+
"Use `nonebot_plugin_htmlrender.backend.playwright.runtime.reconcile_legacy_playwright_cache` instead."
|
|
270
|
+
)
|
|
271
|
+
def clean_playwright_cache(*, cleanup: bool) -> None:
|
|
272
|
+
"""已弃用:清理 Playwright 缓存。"""
|
|
273
|
+
runtime = import_module("nonebot_plugin_htmlrender.backend.playwright.runtime")
|
|
274
|
+
clean_cache = runtime.clean_playwright_cache
|
|
275
|
+
|
|
276
|
+
clean_cache(cleanup=cleanup)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@deprecated(
|
|
280
|
+
"`reconcile_legacy_playwright_cache` from `nonebot_plugin_htmlrender.browser` "
|
|
281
|
+
"is deprecated. Use "
|
|
282
|
+
"`nonebot_plugin_htmlrender.backend.playwright.runtime.reconcile_legacy_playwright_cache` instead."
|
|
283
|
+
)
|
|
284
|
+
def reconcile_legacy_playwright_cache(*, cleanup: bool) -> None:
|
|
285
|
+
"""已弃用:协调旧版 Playwright 缓存目录。"""
|
|
286
|
+
runtime = import_module("nonebot_plugin_htmlrender.backend.playwright.runtime")
|
|
287
|
+
reconcile_cache = runtime.reconcile_legacy_playwright_cache
|
|
288
|
+
|
|
289
|
+
reconcile_cache(cleanup=cleanup)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
__all__ = [
|
|
293
|
+
"_launch",
|
|
294
|
+
"capture_element",
|
|
295
|
+
"clean_playwright_cache",
|
|
296
|
+
"get_browser",
|
|
297
|
+
"get_new_page",
|
|
298
|
+
"html_to_pic",
|
|
299
|
+
"md_to_pic",
|
|
300
|
+
"read_file",
|
|
301
|
+
"read_tpl",
|
|
302
|
+
"reconcile_legacy_playwright_cache",
|
|
303
|
+
"shutdown_htmlrender",
|
|
304
|
+
"startup_htmlrender",
|
|
305
|
+
"template_to_html",
|
|
306
|
+
"template_to_pic",
|
|
307
|
+
"text_to_pic",
|
|
308
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from .base import (
|
|
2
|
+
Backend,
|
|
3
|
+
BackendCapability,
|
|
4
|
+
RenderRuntime,
|
|
5
|
+
RenderSession,
|
|
6
|
+
SupportsHtmlRenderBackend,
|
|
7
|
+
)
|
|
8
|
+
from .factory import (
|
|
9
|
+
BackendAvailability,
|
|
10
|
+
BackendStatus,
|
|
11
|
+
available_backends,
|
|
12
|
+
backend_statuses,
|
|
13
|
+
build_backend,
|
|
14
|
+
get_backend_status,
|
|
15
|
+
is_backend_available,
|
|
16
|
+
is_backend_registered,
|
|
17
|
+
register_backend,
|
|
18
|
+
registered_backends,
|
|
19
|
+
unavailable_backends,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Backend",
|
|
24
|
+
"BackendAvailability",
|
|
25
|
+
"BackendCapability",
|
|
26
|
+
"BackendStatus",
|
|
27
|
+
"RenderRuntime",
|
|
28
|
+
"RenderSession",
|
|
29
|
+
"SupportsHtmlRenderBackend",
|
|
30
|
+
"available_backends",
|
|
31
|
+
"backend_statuses",
|
|
32
|
+
"build_backend",
|
|
33
|
+
"get_backend_status",
|
|
34
|
+
"is_backend_available",
|
|
35
|
+
"is_backend_registered",
|
|
36
|
+
"register_backend",
|
|
37
|
+
"registered_backends",
|
|
38
|
+
"unavailable_backends",
|
|
39
|
+
]
|