♻️ Use persica refactor code

This commit is contained in:
xtaodada 2024-09-21 00:10:00 +08:00
parent 664a47ad6e
commit 3006d6e667
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
23 changed files with 1207 additions and 273 deletions

1
.gitignore vendored
View File

@ -163,3 +163,4 @@ cython_debug/
cache/ cache/
data/ data/
docker-compose.yml docker-compose.yml
.pdm-python

66
main.py
View File

@ -1,58 +1,18 @@
import asyncio from persica.context.application import ApplicationContext
from persica.applicationbuilder import ApplicationBuilder
from signal import signal as signal_fn, SIGINT, SIGTERM, SIGABRT
from src.app import web
from src.bot import bot
from src.env import MIYOUSHE, HOYOLAB, BOT
async def idle(): def main():
task = None app = (
ApplicationBuilder()
def signal_handler(_, __): .set_application_context_class(ApplicationContext)
if web.web_server_task: .set_scanner_packages("src/core")
web.web_server_task.cancel() .build()
task.cancel() )
app.class_scanner.flash("src/plugins")
for s in (SIGINT, SIGTERM, SIGABRT): app.class_scanner.flash("src/route")
signal_fn(s, signal_handler) app.run()
while True:
task = asyncio.create_task(asyncio.sleep(600))
web.bot_main_task = task
try:
await task
except asyncio.CancelledError:
break
async def main():
if MIYOUSHE:
from src.render.article import refresh_recommend_posts
await refresh_recommend_posts()
if HOYOLAB:
from src.render.article_hoyolab import refresh_hoyo_recommend_posts
await refresh_hoyo_recommend_posts()
await web.start()
if BOT:
await bot.start()
try:
await idle()
finally:
if BOT:
try:
await bot.stop()
except RuntimeError:
pass
if web.web_server:
try:
await web.web_server.shutdown()
except AttributeError:
pass
if __name__ == "__main__": if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main()) main()

840
pdm.lock Normal file
View File

@ -0,0 +1,840 @@
# This file is @generated by PDM.
# It is not intended for manual editing.
[metadata]
groups = ["default", "test"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
content_hash = "sha256:268dec44f0ecec5ed8bcdf7cbe20bb3d7b945f16196c3ff5ec721cd01dc19be0"
[[metadata.targets]]
requires_python = ">=3.10"
[[package]]
name = "aiofiles"
version = "24.1.0"
requires_python = ">=3.8"
summary = "File support for asyncio."
groups = ["default"]
files = [
{file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
{file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
]
[[package]]
name = "annotated-types"
version = "0.7.0"
requires_python = ">=3.8"
summary = "Reusable constraint types to use with typing.Annotated"
groups = ["default"]
dependencies = [
"typing-extensions>=4.0.0; python_version < \"3.9\"",
]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
[[package]]
name = "anyio"
version = "4.5.0"
requires_python = ">=3.8"
summary = "High level compatibility layer for multiple asynchronous event loop implementations"
groups = ["default"]
dependencies = [
"exceptiongroup>=1.0.2; python_version < \"3.11\"",
"idna>=2.8",
"sniffio>=1.1",
"typing-extensions>=4.1; python_version < \"3.11\"",
]
files = [
{file = "anyio-4.5.0-py3-none-any.whl", hash = "sha256:fdeb095b7cc5a5563175eedd926ec4ae55413bb4be5770c424af0ba46ccb4a78"},
{file = "anyio-4.5.0.tar.gz", hash = "sha256:c5a275fe5ca0afd788001f58fca1e69e29ce706d746e317d660e21f70c530ef9"},
]
[[package]]
name = "apscheduler"
version = "3.10.4"
requires_python = ">=3.6"
summary = "In-process task scheduler with Cron-like capabilities"
groups = ["default"]
dependencies = [
"importlib-metadata>=3.6.0; python_version < \"3.8\"",
"pytz",
"six>=1.4.0",
"tzlocal!=3.*,>=2.0",
]
files = [
{file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"},
{file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"},
]
[[package]]
name = "beautifulsoup4"
version = "4.12.3"
requires_python = ">=3.6.0"
summary = "Screen-scraping library"
groups = ["default"]
dependencies = [
"soupsieve>1.2",
]
files = [
{file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"},
{file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"},
]
[[package]]
name = "certifi"
version = "2024.8.30"
requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle."
groups = ["default"]
files = [
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
]
[[package]]
name = "click"
version = "8.1.7"
requires_python = ">=3.7"
summary = "Composable command line interface toolkit"
groups = ["default"]
dependencies = [
"colorama; platform_system == \"Windows\"",
"importlib-metadata; python_version < \"3.8\"",
]
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[[package]]
name = "colorama"
version = "0.4.6"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
summary = "Cross-platform colored terminal text."
groups = ["default", "test"]
marker = "sys_platform == \"win32\" or platform_system == \"Windows\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "coloredlogs"
version = "15.0.1"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Colored terminal output for Python's logging module"
groups = ["default"]
dependencies = [
"humanfriendly>=9.1",
]
files = [
{file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
{file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
]
[[package]]
name = "exceptiongroup"
version = "1.2.2"
requires_python = ">=3.7"
summary = "Backport of PEP 654 (exception groups)"
groups = ["default", "test"]
marker = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
]
[[package]]
name = "fastapi"
version = "0.115.0"
requires_python = ">=3.8"
summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
groups = ["default"]
dependencies = [
"pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4",
"starlette<0.39.0,>=0.37.2",
"typing-extensions>=4.8.0",
]
files = [
{file = "fastapi-0.115.0-py3-none-any.whl", hash = "sha256:17ea427674467486e997206a5ab25760f6b09e069f099b96f5b55a32fb6f1631"},
{file = "fastapi-0.115.0.tar.gz", hash = "sha256:f93b4ca3529a8ebc6fc3fcf710e5efa8de3df9b41570958abf1d97d843138004"},
]
[[package]]
name = "filelock"
version = "3.16.1"
requires_python = ">=3.8"
summary = "A platform independent file lock."
groups = ["default"]
files = [
{file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
{file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
]
[[package]]
name = "h11"
version = "0.14.0"
requires_python = ">=3.7"
summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
groups = ["default"]
dependencies = [
"typing-extensions; python_version < \"3.8\"",
]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
[[package]]
name = "httpcore"
version = "1.0.5"
requires_python = ">=3.8"
summary = "A minimal low-level HTTP client."
groups = ["default"]
dependencies = [
"certifi",
"h11<0.15,>=0.13",
]
files = [
{file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"},
{file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"},
]
[[package]]
name = "httpx"
version = "0.27.2"
requires_python = ">=3.8"
summary = "The next generation HTTP client."
groups = ["default"]
dependencies = [
"anyio",
"certifi",
"httpcore==1.*",
"idna",
"sniffio",
]
files = [
{file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"},
{file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"},
]
[[package]]
name = "humanfriendly"
version = "10.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Human friendly output for text interfaces using Python"
groups = ["default"]
dependencies = [
"monotonic; python_version == \"2.7\"",
"pyreadline3; sys_platform == \"win32\" and python_version >= \"3.8\"",
"pyreadline; sys_platform == \"win32\" and python_version < \"3.8\"",
]
files = [
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
]
[[package]]
name = "idna"
version = "3.10"
requires_python = ">=3.6"
summary = "Internationalized Domain Names in Applications (IDNA)"
groups = ["default"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
]
[[package]]
name = "iniconfig"
version = "2.0.0"
requires_python = ">=3.7"
summary = "brain-dead simple config-ini parsing"
groups = ["test"]
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "jinja2"
version = "3.1.4"
requires_python = ">=3.7"
summary = "A very fast and expressive template engine."
groups = ["default"]
dependencies = [
"MarkupSafe>=2.0",
]
files = [
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
]
[[package]]
name = "lxml"
version = "5.3.0"
requires_python = ">=3.6"
summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
groups = ["default"]
files = [
{file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"},
{file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"},
{file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"},
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"},
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"},
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"},
{file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"},
{file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"},
{file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"},
{file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"},
{file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"},
{file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"},
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"},
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"},
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"},
{file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"},
{file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"},
{file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"},
{file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"},
{file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"},
{file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"},
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"},
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"},
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"},
{file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"},
{file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"},
{file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"},
{file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"},
{file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"},
{file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"},
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"},
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"},
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"},
{file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"},
{file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"},
{file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"},
{file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"},
{file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"},
]
[[package]]
name = "markupsafe"
version = "2.1.5"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
groups = ["default"]
files = [
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
{file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
{file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
{file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
{file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
{file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
{file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
{file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
{file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
{file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
{file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
{file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
{file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
{file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
{file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
{file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
{file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
{file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
{file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
{file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
{file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
{file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
{file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
{file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
{file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
{file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
{file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
{file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
{file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
]
[[package]]
name = "networkx"
version = "3.3"
requires_python = ">=3.10"
summary = "Python package for creating and manipulating graphs and networks"
groups = ["default"]
files = [
{file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"},
{file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"},
]
[[package]]
name = "packaging"
version = "24.1"
requires_python = ">=3.8"
summary = "Core utilities for Python packages"
groups = ["test"]
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
[[package]]
name = "persica"
version = "0.1.0a1"
requires_python = ">=3.10"
git = "https://github.com/luoshuijs/Persica"
ref = "dev"
revision = "0ef0f04a7938d7394ada2e2886a9eb70dd21c41e"
summary = "Automatic framework for Pythone"
groups = ["default"]
dependencies = [
"networkx>=3.3",
]
[[package]]
name = "platformdirs"
version = "4.3.6"
requires_python = ">=3.8"
summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
groups = ["default"]
files = [
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
]
[[package]]
name = "pluggy"
version = "1.5.0"
requires_python = ">=3.8"
summary = "plugin and hook calling mechanisms for python"
groups = ["test"]
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
]
[[package]]
name = "pyaes"
version = "1.6.1"
summary = "Pure-Python Implementation of the AES block-cipher and common modes of operation"
groups = ["default"]
files = [
{file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"},
]
[[package]]
name = "pydantic"
version = "2.9.2"
requires_python = ">=3.8"
summary = "Data validation using Python type hints"
groups = ["default"]
dependencies = [
"annotated-types>=0.6.0",
"pydantic-core==2.23.4",
"typing-extensions>=4.12.2; python_version >= \"3.13\"",
"typing-extensions>=4.6.1; python_version < \"3.13\"",
]
files = [
{file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"},
{file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"},
]
[[package]]
name = "pydantic-core"
version = "2.23.4"
requires_python = ">=3.8"
summary = "Core functionality for Pydantic validation and serialization"
groups = ["default"]
dependencies = [
"typing-extensions!=4.7.0,>=4.6.0",
]
files = [
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"},
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"},
{file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"},
{file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"},
{file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"},
{file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"},
{file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"},
{file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"},
{file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"},
{file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"},
{file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"},
{file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"},
{file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"},
{file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"},
{file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"},
{file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"},
{file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"},
{file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"},
{file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"},
{file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"},
{file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"},
{file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"},
{file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"},
{file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"},
{file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"},
]
[[package]]
name = "pyreadline3"
version = "3.5.4"
requires_python = ">=3.8"
summary = "A python implementation of GNU readline."
groups = ["default"]
marker = "sys_platform == \"win32\" and python_version >= \"3.8\""
files = [
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
]
[[package]]
name = "pyrogram"
version = "2.0.124"
requires_python = "~=3.8"
git = "https://github.com/TeamPGM/pyrogram"
revision = "bcfc7c386bea65939775fa02f5e6d40bdccb7c7f"
summary = "Elegant, modern and asynchronous Telegram MTProto API framework in Python for users and bots"
groups = ["default"]
dependencies = [
"pyaes==1.6.1",
"pysocks==1.7.1",
]
[[package]]
name = "pyrotgcrypto"
version = "1.2.7"
requires_python = "~=3.7"
summary = "Fast and Portable Cryptography Extension Library for Pyrogram"
groups = ["default"]
files = [
{file = "PyroTgCrypto-1.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:35b2b5e5162ecea4f754412614243933536466d93c3cf3c857526d861d8c661d"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:991323f7c2d8c2780bd1e5342693bda6d6300205a48732b57ca865a962750fa2"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38202a4672951b350afc209700b88c93f9b75d80c948dc5802f9fe80803a12db"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21f2ff6398036990d51a424ad630b253c455d5e57ce15a24fce1af99af4d9e1f"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29741048e5a54ca13094e0649d867c609feffa264f4ae76964142484f07b800f"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:677fc0517d6c3a94c7d90944bc77827c801af6f75a1a4a20206ceaf1db856ef2"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:64a89f1a251d9cfbbecd5255097c561f1693be54eef455c67ab43f7f5477c851"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9ddf241cfdde91b1f9dc242cddcf95d5b1ead0b446f056f650d029a38410c9da"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b9e02dfa4ceb28a33d6d32b68d8547463713dd848f75304e06aeb9c82f9c446"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-win32.whl", hash = "sha256:61b7a1d70572795100c22129d7d848386e1890c93504dbfb54599474627cf657"},
{file = "PyroTgCrypto-1.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:dc1413f54e5f05eaa4f86525d87c78d765cbbb5f20389db46458fa4e7b429019"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cd81935567e792a57768b3242c268cb8ccc538504c82b4d2ac2cc2e64a23a95"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd965133558d9995635b77d461eb4c12a90b2387b9a2f4d3be0329a0cc03c66d"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4d423d9bf1e15a1527bcfe3a3ff7aa625c7112db97635a3c2f7e9da86f19112"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e364743e762fed1006b6675f2cda117968450205a98f83c8e87b3f337d7fbf3e"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5acda6512167e2a8fdb431ec5919f1bd33b67c3a6802d69f0e7ab6b535968f9f"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72ccd78d50c3480717690f01b8e0533e591017946f02da89a954c863a9da230d"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9b6418477eb7d8d2878a873ff4352947b7c5ff8256bc8f4f714b2636f707f5f1"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0dd9b0e560a1f575bf86ab649757a7ceafd03f858d1a686398b216c5929c936"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:48542a8de389a3a5258df70708b5fdce8c63cf8a068e8cb580cd3a01689f6261"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-win32.whl", hash = "sha256:85a57a10cafafc0f95a8dd7988754f4194b281ac07e6c3e2c7c6065097f0dba9"},
{file = "PyroTgCrypto-1.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:6b58710373939a9c2c520c00666631cd782adbb14434a179d22c5eeae3f0727f"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:75dac820a0ead43bbc8f134f741472d889318d32b4f587e13342a4f412b6e6c8"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3af1a29b6c7392abb060b53dcbdbfc213253b8f891d37dc2890151356ef8ece4"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5a09deeb201de18a7e3ed2b5fca2db421ad5c610d7b6db4a9b29d63df5dae6db"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1306b9f0fbc77be8add4a6f3c68a9d1d005d1bdd970965b6936ca7419820afba"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd99a80f8c104104e30a94a25e7e8c4f190891d3aceaa9f81983358b568c2438"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca1568499a7699c399a92b84775061ce5c617ad87c1e6e1180e01caf60f47c4d"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a7f7c20bb1136afeea3e760e7e07f352787c6f9a681cdeec1b8aad18805443a"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc384fc568f1fcdcfa3ae5b556898c9caa48f61a91ca39767cd52b420b7f1a44"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:222a5c4a243d379db075105aed4f071a377b7dad7e8c02b4055b680033a4a57b"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-win32.whl", hash = "sha256:1eda8e08a39eead928285560029957a2cf4877da3e3cb233649da073a47dc9e8"},
{file = "PyroTgCrypto-1.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:8eff5b2f18fc03b2ddcfd702d9363cb064ee56b470816a5eb2421ee7881b67f4"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:15ade101da138e520f48574e49ea7a44bab13275d019eb21feb5e9d718b6d65c"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8418ecb1a51d484de79502da4b1d7587a32599cd18ef3834f228e04370b1be3e"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a75a8c9177bcd186d37b82ce9964009c8dcf0996626cb40d743f2fa32fc61bf8"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5df7e330f0dfddbb2dae6bc9c8d0ac8acb8842383efe35590801ef247f25485c"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad37d19118656d6e6e0e7e4ff4b6f31247e892924ff1e4170c52d1db1fd22a96"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2b5ecfdd5e1609789e0ae479154661756d60c8c61beb7ed7660139f4fec1e4"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:74446fa32f9a4da4bd95903ce73553d6c9e790d480bf4a99624e56279cbeb2dc"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96814fc33194e5c9114110197690f81b8f60bb65eb0f492d81ba3f048f7d5d9f"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c8775ebefcc3c25fa68f67126ceab6d8c38490e14249d4f80463faed2ae86612"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-win32.whl", hash = "sha256:ddcdb4ce089fe691bdca571d0a6661f6df8c1f5dbb6470e66ae43097457fcdb2"},
{file = "PyroTgCrypto-1.2.7-cp313-cp313-win_amd64.whl", hash = "sha256:bba87c07da6f76fd70ce894abc9d5321c2339aebf7968877e3726f9710f98458"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:021d1f1be6d49c6ff8fd351785c02bcd5e525d9e9bef6a4d3f06ce8e9e1a13eb"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f75d252d6544c88eda9f6273798d5b8d5e41fe5131b5d9accf4770e449bba59b"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d8211806db398ca0432824669755e547b56735eb82e26806ae60e59ebe2661c"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64572319f81e64d52acad145851d03aba74dbe82a32db80e8202bc938ebb395e"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddce8ab3709fb3cb074295187d7b8baade3bf0cf77c26683bfc9631ffcf28740"},
{file = "PyroTgCrypto-1.2.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c83f6f0a8f6c7edba2961a62dc5ffa5bcf24cd69a7f0848c287800c673797fc7"},
]
[[package]]
name = "pysocks"
version = "1.7.1"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
summary = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
groups = ["default"]
files = [
{file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"},
{file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
]
[[package]]
name = "pytest"
version = "8.3.3"
requires_python = ">=3.8"
summary = "pytest: simple powerful testing with Python"
groups = ["test"]
dependencies = [
"colorama; sys_platform == \"win32\"",
"exceptiongroup>=1.0.0rc8; python_version < \"3.11\"",
"iniconfig",
"packaging",
"pluggy<2,>=1.5",
"tomli>=1; python_version < \"3.11\"",
]
files = [
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
]
[[package]]
name = "pytest-asyncio"
version = "0.24.0"
requires_python = ">=3.8"
summary = "Pytest support for asyncio"
groups = ["test"]
dependencies = [
"pytest<9,>=8.2",
]
files = [
{file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"},
{file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"},
]
[[package]]
name = "python-dotenv"
version = "1.0.1"
requires_python = ">=3.8"
summary = "Read key-value pairs from a .env file and set them as environment variables"
groups = ["default"]
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
]
[[package]]
name = "pytz"
version = "2024.2"
summary = "World timezone definitions, modern and historical"
groups = ["default"]
files = [
{file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
{file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
]
[[package]]
name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
groups = ["default"]
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]]
name = "sniffio"
version = "1.3.1"
requires_python = ">=3.7"
summary = "Sniff out which async library your code is running under"
groups = ["default"]
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
[[package]]
name = "soupsieve"
version = "2.6"
requires_python = ">=3.8"
summary = "A modern CSS selector implementation for Beautiful Soup."
groups = ["default"]
files = [
{file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"},
{file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"},
]
[[package]]
name = "starlette"
version = "0.38.5"
requires_python = ">=3.8"
summary = "The little ASGI library that shines."
groups = ["default"]
dependencies = [
"anyio<5,>=3.4.0",
"typing-extensions>=3.10.0; python_version < \"3.10\"",
]
files = [
{file = "starlette-0.38.5-py3-none-any.whl", hash = "sha256:632f420a9d13e3ee2a6f18f437b0a9f1faecb0bc42e1942aa2ea0e379a4c4206"},
{file = "starlette-0.38.5.tar.gz", hash = "sha256:04a92830a9b6eb1442c766199d62260c3d4dc9c4f9188360626b1e0273cb7077"},
]
[[package]]
name = "tomli"
version = "2.0.1"
requires_python = ">=3.7"
summary = "A lil' TOML parser"
groups = ["test"]
marker = "python_version < \"3.11\""
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
groups = ["default"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
]
[[package]]
name = "tzdata"
version = "2024.1"
requires_python = ">=2"
summary = "Provider of IANA time zone data"
groups = ["default"]
marker = "platform_system == \"Windows\""
files = [
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
]
[[package]]
name = "tzlocal"
version = "5.2"
requires_python = ">=3.8"
summary = "tzinfo object for the local timezone"
groups = ["default"]
dependencies = [
"backports-zoneinfo; python_version < \"3.9\"",
"tzdata; platform_system == \"Windows\"",
]
files = [
{file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
{file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
]
[[package]]
name = "uritools"
version = "4.0.3"
requires_python = ">=3.7"
summary = "URI parsing, classification and composition"
groups = ["default"]
files = [
{file = "uritools-4.0.3-py3-none-any.whl", hash = "sha256:bae297d090e69a0451130ffba6f2f1c9477244aa0a5543d66aed2d9f77d0dd9c"},
{file = "uritools-4.0.3.tar.gz", hash = "sha256:ee06a182a9c849464ce9d5fa917539aacc8edd2a4924d1b7aabeeecabcae3bc2"},
]
[[package]]
name = "urlextract"
version = "1.9.0"
summary = "Collects and extracts URLs from given text."
groups = ["default"]
dependencies = [
"filelock",
"idna",
"platformdirs",
"uritools",
]
files = [
{file = "urlextract-1.9.0-py3-none-any.whl", hash = "sha256:f88963532488b1c7c405e21bd162ae97871754ea04b60e18d33ee075b19b82fd"},
{file = "urlextract-1.9.0.tar.gz", hash = "sha256:70508e02ba9df372e25cf0642db367cece273e8712cd0ce78178fc5dd7ea00db"},
]
[[package]]
name = "uvicorn"
version = "0.30.6"
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
dependencies = [
"click>=7.0",
"h11>=0.8",
"typing-extensions>=4.0; python_version < \"3.11\"",
]
files = [
{file = "uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5"},
{file = "uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788"},
]

38
pyproject.toml Normal file
View File

@ -0,0 +1,38 @@
[project]
name = "FixMiYouShe"
version = "0.1.0"
description = "Default template for PDM package"
authors = [
{name = "xtaodada", email = "xtao@xtaolink.cn"},
]
dependencies = [
"httpx>=0.24.1",
"fastapi>=0.110.0",
"starlette",
"uvicorn>=0.23.2",
"pydantic",
"python-dotenv",
"coloredlogs",
"pytz",
"apscheduler",
"aiofiles>=23.2.1",
"jinja2>=3.1.3",
"beautifulsoup4",
"lxml",
"PyroTgCrypto>=1.2.7",
"pyrogram @ git+https://github.com/TeamPGM/pyrogram",
"urlextract",
"persica @ git+https://github.com/luoshuijs/Persica@dev",
]
requires-python = ">=3.10"
readme = "README.md"
license = {text = "AGPL 3.0+"}
[tool.pdm]
distribution = false
[tool.pdm.dev-dependencies]
test = [
"pytest>=8.3.3",
"pytest-asyncio>=0.24.0",
]

View File

@ -1,16 +1,51 @@
httpx==0.24.1 # This file is @generated by PDM.
fastapi~=0.110.0 # Please do not edit it manually.
starlette
uvicorn~=0.23.2 aiofiles==24.1.0
pydantic annotated-types==0.7.0
python-dotenv anyio==4.5.0
coloredlogs apscheduler==3.10.4
pytz beautifulsoup4==4.12.3
apscheduler certifi==2024.8.30
aiofiles==23.2.1 click==8.1.7
jinja2==3.1.3 colorama==0.4.6; sys_platform == "win32" or platform_system == "Windows"
beautifulsoup4 coloredlogs==15.0.1
lxml exceptiongroup==1.2.2; python_version < "3.11"
PyroTgCrypto==1.2.6a0 fastapi==0.115.0
git+https://github.com/TeamPGM/pyrogram filelock==3.16.1
urlextract h11==0.14.0
httpcore==1.0.5
httpx==0.27.2
humanfriendly==10.0
idna==3.10
iniconfig==2.0.0
jinja2==3.1.4
lxml==5.3.0
markupsafe==2.1.5
networkx==3.3
packaging==24.1
persica @ git+https://github.com/luoshuijs/Persica@dev
platformdirs==4.3.6
pluggy==1.5.0
pyaes==1.6.1
pydantic==2.9.2
pydantic-core==2.23.4
pyreadline3==3.5.4; sys_platform == "win32" and python_version >= "3.8"
pyrogram @ git+https://github.com/TeamPGM/pyrogram
pyrotgcrypto==1.2.7
pysocks==1.7.1
pytest==8.3.3
pytest-asyncio==0.24.0
python-dotenv==1.0.1
pytz==2024.2
six==1.16.0
sniffio==1.3.1
soupsieve==2.6
starlette==0.38.5
tomli==2.0.1; python_version < "3.11"
typing-extensions==4.12.2
tzdata==2024.1; platform_system == "Windows"
tzlocal==5.2
uritools==4.0.3
urlextract==1.9.0
uvicorn==0.30.6

View File

@ -1,17 +0,0 @@
from pyrogram import Client
from pathlib import Path
from .env import BOT_API_ID_INT, BOT_API_HASH, BOT_TOKEN
data_path = Path("data")
data_path.mkdir(exist_ok=True)
bot = Client(
"bot",
api_id=int(BOT_API_ID_INT),
api_hash=BOT_API_HASH,
bot_token=BOT_TOKEN,
workdir="data",
plugins=dict(root="src/plugins"),
)

34
src/core/bot.py Normal file
View File

@ -0,0 +1,34 @@
from persica.factory.component import AsyncInitializingComponent
from pyrogram import Client
from pathlib import Path
from src.env import BOT, BOT_API_ID_INT, BOT_API_HASH, BOT_TOKEN
data_path = Path("data")
data_path.mkdir(exist_ok=True)
class TelegramBot(AsyncInitializingComponent):
def __init__(self):
self.bot = Client(
"bot",
api_id=int(BOT_API_ID_INT),
api_hash=BOT_API_HASH,
bot_token=BOT_TOKEN,
workdir="data",
)
async def initialize(self):
if not BOT:
return
await self.bot.start()
async def shutdown(self):
if not BOT:
return
try:
await self.bot.stop()
except RuntimeError:
pass

13
src/core/scheduler.py Normal file
View File

@ -0,0 +1,13 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from fastapi import FastAPI
from persica.factory.component import BaseComponent
class TimeScheduler(BaseComponent):
def __init__(self):
self.scheduler = AsyncIOScheduler(timezone="Asia/ShangHai")
def register_scheduler(self, app: "FastAPI"):
@app.on_event("startup")
async def start_event():
self.scheduler.start()

View File

@ -3,39 +3,33 @@ import asyncio
import uvicorn import uvicorn
from fastapi import FastAPI from fastapi import FastAPI
from persica.factory.component import AsyncInitializingComponent
from starlette.middleware.trustedhost import TrustedHostMiddleware from starlette.middleware.trustedhost import TrustedHostMiddleware
from .env import DOMAIN, DEBUG, PORT from src.core.scheduler import TimeScheduler
from .route import get_routes from src.env import DOMAIN, DEBUG, PORT
from .route.base import UserAgentMiddleware
from .services.scheduler import register_scheduler
app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
class Web: class WebApp(AsyncInitializingComponent):
def __init__(self): def __init__(self, scheduler: TimeScheduler):
self.app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
scheduler.register_scheduler(self.app)
self.web_server = None self.web_server = None
self.web_server_task = None self.web_server_task = None
self.bot_main_task = None
@staticmethod def init_web(self):
def init_web():
if not DEBUG: if not DEBUG:
app.add_middleware( self.app.add_middleware(
TrustedHostMiddleware, TrustedHostMiddleware,
allowed_hosts=[ allowed_hosts=[
DOMAIN, DOMAIN,
], ],
) )
app.add_middleware(UserAgentMiddleware)
get_routes()
register_scheduler(app)
async def start(self): async def start(self):
self.init_web() self.init_web()
self.web_server = uvicorn.Server( self.web_server = uvicorn.Server(
config=uvicorn.Config(app, host="0.0.0.0", port=PORT) config=uvicorn.Config(self.app, host="0.0.0.0", port=PORT)
) )
server_config = self.web_server.config server_config = self.web_server.config
server_config.setup_event_loop() server_config.setup_event_loop()
@ -54,8 +48,14 @@ class Web:
def stop(self): def stop(self):
if self.web_server_task: if self.web_server_task:
self.web_server_task.cancel() self.web_server_task.cancel()
if self.bot_main_task:
self.bot_main_task.cancel()
async def initialize(self):
await self.start()
web = Web() async def shutdown(self):
self.stop()
if self.web_server:
try:
await self.web_server.shutdown()
except AttributeError:
pass

View File

@ -2,16 +2,16 @@
"game_list": [ "game_list": [
{ {
"id": "2", "id": "2",
"icon": "https://fastcdn.hoyoverse.com/static-resource-v2/2023/11/08/9db76fb146f82c045bc276956f86e047_6878380451593228482.png", "icon": "https://fastcdn.hoyoverse.com/static-resource-v2/2024/08/28/477df7dc8ccb9343da4aea31091c4723_802231292277516724.png",
"bg": "https://upload-os-bbs.hoyolab.com/upload/2024/07/11/af3fa25fb0cac1959da97b6b867fdb57_6289156149732603194.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70", "bg": "https://upload-os-bbs.hoyolab.com/upload/2024/08/22/2c103142df58ff983fcd3bc47d397c49_3439523162404792698.png?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70",
"name": "原神", "name": "原神",
"bg_color": "#244C74", "bg_color": "#6E2C14",
"focus_channel_id": "30" "focus_channel_id": "30"
}, },
{ {
"id": "6", "id": "6",
"icon": "https://hyl-static-res-prod.hoyolab.com/communityweb/business/starrail_hoyoverse.png", "icon": "https://hyl-static-res-prod.hoyolab.com/communityweb/business/starrail_hoyoverse.png",
"bg": "https://upload-os-bbs.hoyolab.com/upload/2024/07/31/8981eebc4cd223331a0eedaca9b73f19_928166619611008481.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70", "bg": "https://upload-os-bbs.hoyolab.com/upload/2024/09/10/a2e1dbea2d1b7af095941428eb233f95_5829553462118520641.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70",
"name": "崩坏:星穹铁道", "name": "崩坏:星穹铁道",
"bg_color": "#101521", "bg_color": "#101521",
"focus_channel_id": "42" "focus_channel_id": "42"
@ -19,7 +19,7 @@
{ {
"id": "8", "id": "8",
"icon": "https://hyl-static-res-prod.hoyolab.com/communityweb/business/nap.png", "icon": "https://hyl-static-res-prod.hoyolab.com/communityweb/business/nap.png",
"bg": "https://upload-os-bbs.hoyolab.com/upload/2024/06/28/1f817e30accd6c117aba10760c52552f_1609948843932447239.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70", "bg": "https://upload-os-bbs.hoyolab.com/upload/2024/08/13/d0ebd742d2afe541118c14d2d863118e_7814679909409111693.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70",
"name": "绝区零", "name": "绝区零",
"bg_color": "#F5F6FB", "bg_color": "#F5F6FB",
"focus_channel_id": "46" "focus_channel_id": "46"
@ -27,9 +27,9 @@
{ {
"id": "1", "id": "1",
"icon": "https://fastcdn.hoyoverse.com/static-resource-v2/2024/02/29/3d96534fd7a35a725f7884e6137346d1_3942255444511793944.png", "icon": "https://fastcdn.hoyoverse.com/static-resource-v2/2024/02/29/3d96534fd7a35a725f7884e6137346d1_3942255444511793944.png",
"bg": "https://upload-os-bbs.hoyolab.com/upload/2024/07/24/c6e8a685963be61470df222b71e28a3f_2653988210193011390.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70", "bg": "https://upload-os-bbs.hoyolab.com/upload/2024/09/02/ef9669e2ec4f331407d265aa5d5eb4c1_7138618278434371705.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70",
"name": "Honkai Impact 3rd", "name": "Honkai Impact 3rd",
"bg_color": "#581312", "bg_color": "#292180",
"focus_channel_id": "0" "focus_channel_id": "0"
}, },
{ {
@ -42,7 +42,7 @@
}, },
{ {
"id": "5", "id": "5",
"icon": "https://webstatic.hoyoverse.com/upload/static-resource/2022/08/04/8a31e3d6bce7684556cd45b1e1c309bf_1216320235452608527.png", "icon": "https://hyl-static-res-prod.hoyolab.com/communityWeb/pgc/business/hyl_icon.png",
"bg": "https://upload-os-bbs.hoyolab.com/upload/2024/08/09/1e4a3ac09f82fd7f7702c3ec19dc38fd_7412144515818250508.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70", "bg": "https://upload-os-bbs.hoyolab.com/upload/2024/08/09/1e4a3ac09f82fd7f7702c3ec19dc38fd_7412144515818250508.jpg?x-oss-process=image/auto-orient,0/interlace,1/format,webp/quality,q_70",
"name": "HoYoLAB", "name": "HoYoLAB",
"bg_color": "#61C1F2", "bg_color": "#61C1F2",

View File

@ -1,5 +1,7 @@
from typing import List, Optional from typing import List, Optional
from persica.factory.component import BaseComponent
from pyrogram import Client
from pyrogram.types import ( from pyrogram.types import (
InputTextMessageContent, InputTextMessageContent,
InlineQueryResultArticle, InlineQueryResultArticle,
@ -9,14 +11,14 @@ from pyrogram.types import (
InlineQueryResultDocument, InlineQueryResultDocument,
) )
from src.core.bot import TelegramBot
from .start import get_test_button from .start import get_test_button
from ..api.bot_request import get_post_info from ..api.bot_request import get_post_info
from ..api.models import PostInfo from ..api.models import PostInfo
from ..bot import bot
from ..utils.url import get_lab_link from ..utils.url import get_lab_link
def get_help_article() -> InlineQueryResultArticle: def get_help_article(bot: Client) -> InlineQueryResultArticle:
text = f"欢迎使用 @{bot.me.username} 来转换 米游社/HoYoLab 链接,您也可以将 Bot 添加到群组或频道自动匹配消息。" text = f"欢迎使用 @{bot.me.username} 来转换 米游社/HoYoLab 链接,您也可以将 Bot 添加到群组或频道自动匹配消息。"
return InlineQueryResultArticle( return InlineQueryResultArticle(
title=">> 帮助 <<", title=">> 帮助 <<",
@ -72,10 +74,9 @@ async def add_document_results(
return result return result
@bot.on_inline_query() async def inline(bot: Client, query: InlineQuery):
async def inline(_, query: InlineQuery):
message = query.query message = query.query
results = [get_help_article()] results = [get_help_article(bot)]
if message: if message:
replace_list = get_lab_link(message) replace_list = get_lab_link(message)
if replace_list: if replace_list:
@ -98,3 +99,10 @@ async def inline(_, query: InlineQuery):
switch_pm_parameter="start", switch_pm_parameter="start",
results=results, results=results,
) )
class InlineBotPlugin(BaseComponent):
def __init__(self, telegram_bot: TelegramBot):
@telegram_bot.bot.on_inline_query()
async def inline_query(_, query: InlineQuery):
await inline(_, query)

View File

@ -1,11 +1,12 @@
from asyncio import sleep from asyncio import sleep
from persica.factory.component import BaseComponent
from pyrogram import filters from pyrogram import filters
from pyrogram.enums import MessageEntityType, ChatType from pyrogram.enums import MessageEntityType, ChatType
from pyrogram.errors import WebpageNotFound from pyrogram.errors import WebpageNotFound
from pyrogram.types import Message, MessageEntity from pyrogram.types import Message, MessageEntity
from src.bot import bot from src.core.bot import TelegramBot
from src.log import logger from src.log import logger
from src.utils.url import get_lab_link from src.utils.url import get_lab_link
@ -80,15 +81,6 @@ async def process_link_func(markdown_text: str, message: Message):
await sleep(0.5) await sleep(0.5)
@bot.on_message(
filters=filters.incoming
& ~filters.via_bot
& need_text
& need_chat
& ~forward_from_bot
& ~forward_in_group,
group=1,
)
async def process_link(_, message: Message): async def process_link(_, message: Message):
text = message.text or message.caption text = message.text or message.caption
markdown_text = text.markdown markdown_text = text.markdown
@ -99,13 +91,6 @@ async def process_link(_, message: Message):
await process_link_func(markdown_text, message) await process_link_func(markdown_text, message)
@bot.on_message(
filters=filters.incoming
& filters.command("parse")
& ~filters.forwarded
& ~filters.via_bot
& need_chat,
)
async def parse_reply_link(_, message: Message): async def parse_reply_link(_, message: Message):
reply = message.reply_to_message reply = message.reply_to_message
if not reply: if not reply:
@ -117,3 +102,28 @@ async def parse_reply_link(_, message: Message):
if not markdown_text: if not markdown_text:
return return
await process_link_func(markdown_text, reply) await process_link_func(markdown_text, reply)
class MessageBotPlugin(BaseComponent):
def __init__(self, telegram_bot: TelegramBot):
@telegram_bot.bot.on_message(
filters=filters.incoming
& ~filters.via_bot
& need_text
& need_chat
& ~forward_from_bot
& ~forward_in_group,
group=1,
)
async def _process_link(_, message: Message):
await process_link(_, message)
@telegram_bot.bot.on_message(
filters=filters.incoming
& filters.command("parse")
& ~filters.forwarded
& ~filters.via_bot
& need_chat,
)
async def _parse_reply_link(_, message: Message):
await parse_reply_link(_, message)

View File

@ -1,12 +1,12 @@
import contextlib import contextlib
from datetime import datetime, timedelta from asyncio import sleep
from persica.factory.component import BaseComponent
from pyrogram import filters from pyrogram import filters
from pyrogram.enums import ChatType from pyrogram.enums import ChatType
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
from src.bot import bot from src.core.bot import TelegramBot
from src.services.scheduler import scheduler
HELP_MSG = "此 BOT 将会自动回复可以转换成 Telegram 预览的 URL 链接,可以提供更直观、方便的浏览体验。" HELP_MSG = "此 BOT 将会自动回复可以转换成 Telegram 预览的 URL 链接,可以提供更直观、方便的浏览体验。"
TEST_URL = "https://m.miyoushe.com/ys?channel=xiaomi/#/article/51867765" TEST_URL = "https://m.miyoushe.com/ys?channel=xiaomi/#/article/51867765"
@ -25,21 +25,6 @@ def get_test_button() -> InlineKeyboardMarkup:
) )
async def delete_message(message: Message):
with contextlib.suppress(Exception):
await message.delete()
def add_delete_message_task(message: Message):
scheduler.add_job(
delete_message,
"date",
run_date=datetime.now() + timedelta(seconds=60),
args=(message,),
)
@bot.on_message(filters=filters.command("start"))
async def start(_, message: "Message"): async def start(_, message: "Message"):
reply = await message.reply_text( reply = await message.reply_text(
HELP_MSG, HELP_MSG,
@ -47,4 +32,13 @@ async def start(_, message: "Message"):
reply_markup=get_test_button(), reply_markup=get_test_button(),
) )
if message.chat and message.chat.type in [ChatType.GROUP, ChatType.SUPERGROUP]: if message.chat and message.chat.type in [ChatType.GROUP, ChatType.SUPERGROUP]:
add_delete_message_task(reply) await sleep(30)
with contextlib.suppress(Exception):
await reply.delete()
class StartBotPlugin(BaseComponent):
def __init__(self, telegram_bot: TelegramBot):
@telegram_bot.bot.on_message(filters=filters.command("start"))
async def _start(_, message: "Message"):
await start(_, message)

View File

@ -18,10 +18,9 @@ from src.api.models import (
clean_url, clean_url,
) )
from src.data.get_bg import BG_MAP from src.data.get_bg import BG_MAP
from src.env import DOMAIN, MIYOUSHE from src.env import DOMAIN
from src.error import ArticleNotFoundError from src.error import ArticleNotFoundError
from src.log import logger from src.log import logger
from src.services.scheduler import scheduler
RECOMMEND_POST_MAP: Dict[str, List[PostRecommend]] = {} RECOMMEND_POST_MAP: Dict[str, List[PostRecommend]] = {}
template = template_env.get_template("article.jinja2") template = template_env.get_template("article.jinja2")
@ -227,17 +226,14 @@ async def process_article(game_id: str, post_id: int, i18n: I18n = I18n()) -> st
return content # noqa return content # noqa
if MIYOUSHE: async def refresh_recommend_posts():
logger.info("Start to refresh recommend posts")
@scheduler.scheduled_job("cron", minute="0", second="10") async with Hyperion() as hyperion:
async def refresh_recommend_posts(): for key, gids in GAME_ID_MAP.items():
logger.info("Start to refresh recommend posts") try:
async with Hyperion() as hyperion: RECOMMEND_POST_MAP[key] = await hyperion.get_official_recommended_posts(
for key, gids in GAME_ID_MAP.items(): gids
try: )
RECOMMEND_POST_MAP[key] = ( except Exception as _:
await hyperion.get_official_recommended_posts(gids) logger.exception(f"Failed to get recommend posts gids={gids}")
) logger.info("Finish to refresh recommend posts")
except Exception as _:
logger.exception(f"Failed to get recommend posts gids={gids}")
logger.info("Finish to refresh recommend posts")

View File

@ -4,7 +4,6 @@ from typing import Dict, List, Callable
from src.api.hoyolab import Hoyolab from src.api.hoyolab import Hoyolab
from src.api.i18n import I18n, i18n_alias from src.api.i18n import I18n, i18n_alias
from src.api.models import PostRecommend, PostType, PostInfo from src.api.models import PostRecommend, PostType, PostInfo
from src.env import HOYOLAB
from src.log import logger from src.log import logger
from src.render.article import ( from src.render.article import (
process_article_text, process_article_text,
@ -12,7 +11,6 @@ from src.render.article import (
template, template,
get_public_data, get_public_data,
) )
from src.services.scheduler import scheduler
GAME_ID_MAP = {"bh3": 1, "ys": 2, "wd": 4, "dby": 5, "sr": 6, "zzz": 8} GAME_ID_MAP = {"bh3": 1, "ys": 2, "wd": 4, "dby": 5, "sr": 6, "zzz": 8}
RECOMMEND_POST_MAP: Dict[int, List[PostRecommend]] = {} RECOMMEND_POST_MAP: Dict[int, List[PostRecommend]] = {}
@ -75,20 +73,17 @@ async def process_article(post_id: int, lang: str) -> str:
return content # noqa return content # noqa
if HOYOLAB: async def refresh_hoyo_recommend_posts():
logger.info("Start to refresh hoyolab recommend posts")
@scheduler.scheduled_job("cron", minute="0", second="10") async with Hoyolab() as hoyolab:
async def refresh_hoyo_recommend_posts(): for gids in GAME_ID_MAP.values():
logger.info("Start to refresh hoyolab recommend posts") temp = []
async with Hoyolab() as hoyolab: for k in (1, 2, 3):
for gids in GAME_ID_MAP.values(): try:
temp = [] temp.extend(await hoyolab.get_news_recommend(gids, type_=k))
for k in (1, 2, 3): except Exception as _:
try: logger.exception(
temp.extend(await hoyolab.get_news_recommend(gids, type_=k)) f"Failed to get recommend posts gids={gids} type={k}"
except Exception as _: )
logger.exception( RECOMMEND_POST_MAP[gids] = temp
f"Failed to get recommend posts gids={gids} type={k}" logger.info("Finish to refresh hoyolab recommend posts")
)
RECOMMEND_POST_MAP[gids] = temp
logger.info("Finish to refresh hoyolab recommend posts")

View File

@ -1,18 +0,0 @@
from src.env import MIYOUSHE, HOYOLAB
def get_routes():
from .error import validation_exception_handler
routes = [
validation_exception_handler,
]
if MIYOUSHE:
from .article import parse_article
routes.append(parse_article)
if HOYOLAB:
from .article_hoyolab import parse_hoyo_article
routes.append(parse_hoyo_article)

View File

@ -1,39 +1,57 @@
from persica.factory.component import AsyncInitializingComponent
from starlette.requests import Request from starlette.requests import Request
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
from .base import get_redirect_response from .base import get_redirect_response
from ..app import app
from ..error import ArticleError, ResponseException from src.core.web_app import WebApp
from ..log import logger from src.core.scheduler import TimeScheduler
from ..render.article import process_article, get_post_info from src.env import MIYOUSHE
from src.error import ArticleError, ResponseException
from src.log import logger
from src.render.article import process_article, get_post_info, refresh_recommend_posts
@app.get("/{game_id}/article/{post_id}") class ArticlePlugin(AsyncInitializingComponent):
async def parse_article(game_id: str, post_id: int, request: Request): def __init__(self, web_app: WebApp, sche: TimeScheduler):
try: if not MIYOUSHE:
return HTMLResponse(await process_article(game_id, post_id)) return
except ResponseException as e: web_app.app.add_api_route("/{game_id}/article/{post_id}", self.parse_article)
logger.warning(e.message) web_app.app.add_api_route(
return get_redirect_response(request) "/{game_id}/article/{post_id}/json", self.parse_article_json
except ArticleError as e:
logger.warning(e.msg)
return get_redirect_response(request)
except Exception as _:
logger.exception(
"Failed to get article game_id[%s] post_id[%s]", game_id, post_id
) )
return get_redirect_response(request) sche.scheduler.add_job(refresh_recommend_posts, "cron", minute="0", second="10")
async def initialize(self):
if not MIYOUSHE:
return
await refresh_recommend_posts()
@app.get("/{game_id}/article/{post_id}/json") @staticmethod
async def parse_article_json(game_id: str, post_id: int, request: Request): async def parse_article(game_id: str, post_id: int, request: Request):
try: try:
return await get_post_info(game_id, post_id) return HTMLResponse(await process_article(game_id, post_id))
except ArticleError as e: except ResponseException as e:
logger.warning(e.msg) logger.warning(e.message)
return get_redirect_response(request) return get_redirect_response(request)
except Exception as _: except ArticleError as e:
logger.exception( logger.warning(e.msg)
"Failed to get article game_id[%s] post_id[%s]", game_id, post_id return get_redirect_response(request)
) except Exception as _:
return get_redirect_response(request) logger.exception(
"Failed to get article game_id[%s] post_id[%s]", game_id, post_id
)
return get_redirect_response(request)
@staticmethod
async def parse_article_json(game_id: str, post_id: int, request: Request):
try:
return await get_post_info(game_id, post_id)
except ArticleError as e:
logger.warning(e.msg)
return get_redirect_response(request)
except Exception as _:
logger.exception(
"Failed to get article game_id[%s] post_id[%s]", game_id, post_id
)
return get_redirect_response(request)

View File

@ -1,26 +1,48 @@
from persica.factory.component import AsyncInitializingComponent
from starlette.requests import Request from starlette.requests import Request
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
from .base import get_redirect_response from .base import get_redirect_response
from ..app import app
from ..error import ArticleError, ResponseException from src.core.web_app import WebApp
from ..log import logger from src.core.scheduler import TimeScheduler
from ..render.article_hoyolab import process_article, get_post_info from src.env import HOYOLAB
from src.error import ArticleError, ResponseException
from src.log import logger
from src.render.article_hoyolab import (
process_article,
get_post_info,
refresh_hoyo_recommend_posts,
)
@app.get("/article/{post_id}") class ArticleHoYoPlugin(AsyncInitializingComponent):
@app.get("/article/{post_id}/{lang}") def __init__(self, web_app: WebApp, sche: TimeScheduler):
async def parse_hoyo_article(post_id: int, request: Request, lang: str = "zh-cn"): if not HOYOLAB:
try: return
if lang == "json": web_app.app.add_api_route("/article/{post_id}", self.parse_hoyo_article)
return await get_post_info(post_id, "zh-cn") web_app.app.add_api_route("/article/{post_id}/{lang}", self.parse_hoyo_article)
return HTMLResponse(await process_article(post_id, lang)) sche.scheduler.add_job(
except ResponseException as e: refresh_hoyo_recommend_posts, "cron", minute="0", second="20"
logger.warning(e.message) )
return get_redirect_response(request)
except ArticleError as e: async def initialize(self):
logger.warning(e.msg) if not HOYOLAB:
return get_redirect_response(request) return
except Exception as _: await refresh_hoyo_recommend_posts()
logger.exception(f"Failed to get article {post_id} lang {lang}")
return get_redirect_response(request) @staticmethod
async def parse_hoyo_article(post_id: int, request: Request, lang: str = "zh-cn"):
try:
if lang == "json":
return await get_post_info(post_id, "zh-cn")
return HTMLResponse(await process_article(post_id, lang))
except ResponseException as e:
logger.warning(e.message)
return get_redirect_response(request)
except ArticleError as e:
logger.warning(e.msg)
return get_redirect_response(request)
except Exception as _:
logger.exception(f"Failed to get article {post_id} lang {lang}")
return get_redirect_response(request)

View File

@ -1,9 +1,11 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from persica.factory.component import BaseComponent
from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import RedirectResponse from starlette.responses import RedirectResponse
from src.env import MIYOUSHE from src.core.web_app import WebApp
from src.env import MIYOUSHE, DEBUG
if TYPE_CHECKING: if TYPE_CHECKING:
from starlette.middleware.base import RequestResponseEndpoint from starlette.middleware.base import RequestResponseEndpoint
@ -26,3 +28,9 @@ class UserAgentMiddleware(BaseHTTPMiddleware):
if (not user_agent) or ("telegram" not in user_agent.lower()): if (not user_agent) or ("telegram" not in user_agent.lower()):
return get_redirect_response(request) return get_redirect_response(request)
return await call_next(request) return await call_next(request)
class BaseRoutePlugin(BaseComponent):
def __init__(self, web_app: WebApp):
if not DEBUG:
web_app.app.add_middleware(UserAgentMiddleware)

View File

@ -1,11 +1,18 @@
from fastapi.exceptions import RequestValidationError from fastapi.exceptions import RequestValidationError
from persica.factory.component import BaseComponent
from starlette.requests import Request from starlette.requests import Request
from src.app import app from src.core.web_app import WebApp
from src.route.base import get_redirect_response from src.route.base import get_redirect_response
@app.exception_handler(RequestValidationError) class ErrorRoutePlugin(BaseComponent):
@app.exception_handler(404) def __init__(self, web_app: WebApp):
async def validation_exception_handler(request: "Request", _): web_app.app.add_exception_handler(
return get_redirect_response(request) RequestValidationError, self.validation_exception_handler
)
web_app.app.add_exception_handler(404, self.validation_exception_handler)
@staticmethod
async def validation_exception_handler(request: "Request", _):
return get_redirect_response(request)

View File

@ -1,10 +0,0 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from fastapi import FastAPI
scheduler = AsyncIOScheduler(timezone="Asia/ShangHai")
def register_scheduler(app: "FastAPI"):
@app.on_event("startup")
async def start_event():
scheduler.start()

0
tests/__init__.py Normal file
View File