diff --git a/.gitignore b/.gitignore index c73f481..5e75384 100644 --- a/.gitignore +++ b/.gitignore @@ -167,3 +167,4 @@ cython_debug/ data/ wakatime.db bot.py +shortcut.db.** diff --git a/nonebot_plugin_wakatime/__init__.py b/nonebot_plugin_wakatime/__init__.py index 65c7748..3fd7ad1 100644 --- a/nonebot_plugin_wakatime/__init__.py +++ b/nonebot_plugin_wakatime/__init__.py @@ -11,6 +11,7 @@ require("nonebot_plugin_orm") require("nonebot_plugin_user") +require("nonebot_plugin_argot") require("nonebot_plugin_alconna") require("nonebot_plugin_htmlrender") require("nonebot_plugin_localstore") @@ -25,6 +26,7 @@ from .config import Config from .schema import WakaTime from .render_pic import render +from .utils import get_background_image from .mount import State, WaitingRecord, waiting_codes from .exception import BindUserException, UserUnboundException from .bootstrap import client_id, mountable, redirect_uri, plugin_enable @@ -102,11 +104,24 @@ async def _(user_session: UserSession, target: Match[At | int]): .finish(at_sender=True, fallback=FallbackStrategy.ignore) ) + background_image = await get_background_image() + result = WakaTime( - user=user_info, stats=stats_info, all_time_since_today=all_time_since_today + user=user_info, + stats=stats_info, + all_time_since_today=all_time_since_today, + background_image=str(background_image), ) image = await render(result) - await UniMessage.image(raw=image).finish(at_sender=True) + await UniMessage.image(raw=image).finish( + at_sender=True, + argot={ + "name": "background", + "command": "background", + "content": str(background_image), + "expire": 300, + }, + ) @wakatime.assign("bind") diff --git a/nonebot_plugin_wakatime/models.py b/nonebot_plugin_wakatime/models.py index 5b010c8..91536a3 100644 --- a/nonebot_plugin_wakatime/models.py +++ b/nonebot_plugin_wakatime/models.py @@ -9,5 +9,5 @@ class User(Model): id: Mapped[int] = mapped_column(primary_key=True) """User ID""" - access_token: Mapped[str] = mapped_column(Text()) + access_token: Mapped[str] = mapped_column(Text) """Wakatime Access Token""" diff --git a/nonebot_plugin_wakatime/render_pic.py b/nonebot_plugin_wakatime/render_pic.py index 6d1c4eb..eb78c4f 100644 --- a/nonebot_plugin_wakatime/render_pic.py +++ b/nonebot_plugin_wakatime/render_pic.py @@ -3,8 +3,8 @@ from nonebot_plugin_htmlrender import template_to_pic, template_to_html from .schema import WakaTime -from .config import RESOURCES_DIR, TEMPLATES_DIR, CustomSource, config -from .utils import image_to_base64, get_lolicon_image, calc_work_time_percentage +from .config import TEMPLATES_DIR +from .utils import calc_work_time_percentage async def render(data: WakaTime) -> bytes: @@ -13,24 +13,12 @@ async def render(data: WakaTime) -> bytes: data["user"]["created_at"], "%Y-%m-%dT%H:%M:%SZ" ).strftime("%b %d %Y") - default_background = RESOURCES_DIR / "images" / "background.png" - - match config.background_source: - case "default": - background_image = image_to_base64(default_background) - case "LoliAPI": - background_image = "https://www.loliapi.com/acg/pe/" - case "Lolicon": - background_image = await get_lolicon_image() - case CustomSource() as cs: - background_image = cs.to_uri() - return await template_to_pic( template_path=str(TEMPLATES_DIR), template_name="profile.html", templates={ "user": data["user"], - "background_image": background_image, + "background_image": data["background_image"], "insights": { "data": data["stats"], "last_week": calc_work_time_percentage( diff --git a/nonebot_plugin_wakatime/schema/__init__.py b/nonebot_plugin_wakatime/schema/__init__.py index 37d9406..2db6980 100644 --- a/nonebot_plugin_wakatime/schema/__init__.py +++ b/nonebot_plugin_wakatime/schema/__init__.py @@ -8,3 +8,4 @@ class WakaTime(TypedDict): user: Users stats: Stats all_time_since_today: str + background_image: str diff --git a/nonebot_plugin_wakatime/utils.py b/nonebot_plugin_wakatime/utils.py index 048f734..bc4fda0 100644 --- a/nonebot_plugin_wakatime/utils.py +++ b/nonebot_plugin_wakatime/utils.py @@ -4,6 +4,9 @@ from typing import Literal import httpx +from pydantic_core import Url + +from .config import RESOURCES_DIR, CustomSource, config def image_to_base64(image_path: Path) -> str: @@ -19,6 +22,25 @@ async def get_lolicon_image() -> str: return response.json()["data"][0]["urls"]["original"] +async def get_background_image() -> str | Url: + + default_background = RESOURCES_DIR / "images" / "background.png" + + match config.background_source: + case "default": + background_image = image_to_base64(default_background) + case "LoliAPI": + background_image = "https://www.loliapi.com/acg/pe/" + case "Lolicon": + background_image = await get_lolicon_image() + case CustomSource() as cs: + background_image = cs.to_uri() + case _: + background_image = image_to_base64(default_background) + + return background_image + + def parse_time(work_time: str): patterns = { diff --git a/pdm.lock b/pdm.lock index ddf6bb1..990a541 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "adapters", "dev", "extra", "tests"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:d46ead06b11fa35fd2322a7fb051b8ffcd0b9ab127c35f10f9d0a8a7e88a5aed" +content_hash = "sha256:304342da789be9cb83367ca8e3644a2b2f8423fd0c96cc4839d23f2eb9222614" [[metadata.targets]] requires_python = ">=3.10" @@ -98,35 +98,52 @@ files = [ {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] +[[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 = "arclet-alconna" -version = "1.8.19" +version = "1.8.26" requires_python = ">=3.8" summary = "A High-performance, Generality, Humane Command Line Arguments Parser Library." groups = ["default"] dependencies = [ - "nepattern<1.0.0,>=0.7.3", - "tarina>=0.5.0", + "nepattern<1.0.0,>=0.7.6", + "tarina>=0.5.5", "typing-extensions>=4.5.0", ] files = [ - {file = "arclet_alconna-1.8.19-py3-none-any.whl", hash = "sha256:c78d5527d8ea13990e96f996a3480bf236ad63b81114f53ce2c010bc2a0ee1d8"}, - {file = "arclet_alconna-1.8.19.tar.gz", hash = "sha256:12064caad6854a4b00dc5b7376d86e15911072acd9278531bf86e4fb97568288"}, + {file = "arclet_alconna-1.8.26-py3-none-any.whl", hash = "sha256:9726c31947efb2cf6786c4a7962f6824e3b2831bb5c45991f2660adfe3958818"}, + {file = "arclet_alconna-1.8.26.tar.gz", hash = "sha256:8acbfc5892aea25772105581cc5e69e765ff4947ac53014ec7feeb5991e0a4e1"}, ] [[package]] name = "arclet-alconna-tools" -version = "0.7.6" +version = "0.7.9" requires_python = ">=3.8" summary = "Builtin Tools for Alconna" groups = ["default"] dependencies = [ - "arclet-alconna>=1.8.15", + "arclet-alconna>=1.8.21", "nepattern<1.0.0,>=0.7.3", ] files = [ - {file = "arclet_alconna_tools-0.7.6-py3-none-any.whl", hash = "sha256:fdd1cb900603ce6bb00295bf7bf7f60dfdb764f0614abe248cdcb754e5149edd"}, - {file = "arclet_alconna_tools-0.7.6.tar.gz", hash = "sha256:7cb7dc54c1c2198529c63227739423401051b8489374f1a7a3efa0c4e70b2a22"}, + {file = "arclet_alconna_tools-0.7.9-py3-none-any.whl", hash = "sha256:01a3462bb9f8dbe55010b394f7a0ac11e331799d463e326738870dce191aa608"}, + {file = "arclet_alconna_tools-0.7.9.tar.gz", hash = "sha256:bded24c4157e13e2d803fe7b77ee246fda456206451337015513f150d1e4449c"}, ] [[package]] @@ -1212,7 +1229,7 @@ files = [ [[package]] name = "nepattern" -version = "0.7.4" +version = "0.7.6" requires_python = ">=3.8" summary = "a complex pattern, support typing" groups = ["default"] @@ -1221,8 +1238,8 @@ dependencies = [ "typing-extensions>=4.5.0", ] files = [ - {file = "nepattern-0.7.4-py3-none-any.whl", hash = "sha256:ad7287ee2ff46f010b8c758bf9ed8fd8141aa1afce29c5d5a4f94cc85d277e6e"}, - {file = "nepattern-0.7.4.tar.gz", hash = "sha256:255a042b45e9d2b04f3c2d73b81912c6b856fae1a10a6e4df30b08ed892d2f9c"}, + {file = "nepattern-0.7.6-py3-none-any.whl", hash = "sha256:233d0befecc190f228ded3651a85faaf53f1308bba40ab8ddec379d0d3c88051"}, + {file = "nepattern-0.7.6.tar.gz", hash = "sha256:07bd5b2f3b9b9739b703bf723ffd642ca93738a32df7b699d57d6f338d46bad0"}, ] [[package]] @@ -1271,22 +1288,55 @@ files = [ [[package]] name = "nonebot-plugin-alconna" -version = "0.50.0" +version = "0.51.4" requires_python = ">=3.9" summary = "Alconna Adapter for Nonebot" groups = ["default"] dependencies = [ - "arclet-alconna-tools>=0.7.6", - "arclet-alconna>=1.8.19", + "arclet-alconna-tools>=0.7.9", + "arclet-alconna>=1.8.25", "importlib-metadata>=4.13.0", "nepattern>=0.7.4", "nonebot-plugin-waiter>=0.6.0", "nonebot2>=2.3.0", - "tarina>=0.5.4", + "tarina>=0.5.5", +] +files = [ + {file = "nonebot_plugin_alconna-0.51.4-py3-none-any.whl", hash = "sha256:9d31e537eb35e45a3753ad5d95dc0359f777269d6ce7e39fa74d515cad9a0981"}, + {file = "nonebot_plugin_alconna-0.51.4.tar.gz", hash = "sha256:a43720a497c4fefb0da89e8d9996f8261bb0e92f70a991f2f4fd14c8ed628995"}, +] + +[[package]] +name = "nonebot-plugin-apscheduler" +version = "0.5.0" +requires_python = "<4.0,>=3.9" +summary = "APScheduler Support for NoneBot2" +groups = ["default"] +dependencies = [ + "apscheduler<4.0.0,>=3.7.0", + "nonebot2<3.0.0,>=2.2.0", + "pydantic!=2.5.0,!=2.5.1,<3.0.0,>=1.10.0", +] +files = [ + {file = "nonebot_plugin_apscheduler-0.5.0-py3-none-any.whl", hash = "sha256:8b99b5ee60c4bc195d4df2fd27dab3d6963691e3332f6cee31a06eb4277c307f"}, + {file = "nonebot_plugin_apscheduler-0.5.0.tar.gz", hash = "sha256:6c0230e99765f275dc83d6639ff33bd6f71203fa10cd1b8a204b0f95530cda86"}, +] + +[[package]] +name = "nonebot-plugin-argot" +version = "0.1.1" +requires_python = ">=3.10" +summary = "NoneBot 暗语" +groups = ["default"] +dependencies = [ + "nonebot-plugin-alconna>=0.51.1", + "nonebot-plugin-apscheduler>=0.5.0", + "nonebot-plugin-orm>=0.7.6", + "nonebot2>=2.3.2", ] files = [ - {file = "nonebot_plugin_alconna-0.50.0-py3-none-any.whl", hash = "sha256:69423404d29a8bda3506446743d090f5913c2973db2c810d379cb595db7f9a56"}, - {file = "nonebot_plugin_alconna-0.50.0.tar.gz", hash = "sha256:deccaed139fc4e67eff4c88d0921bc5e5fbeb5235250694be150829304b6388e"}, + {file = "nonebot_plugin_argot-0.1.1-py3-none-any.whl", hash = "sha256:71bc4251a886513d0fa287395dddc85caf9cd07c0bb38ec55c46e392831f7f6d"}, + {file = "nonebot_plugin_argot-0.1.1.tar.gz", hash = "sha256:da770630dd06092637488b19458c1c7848ff70a58666afc5aefdbf4e211dfe2e"}, ] [[package]] @@ -1328,7 +1378,7 @@ files = [ [[package]] name = "nonebot-plugin-orm" -version = "0.7.5" +version = "0.7.6" requires_python = "<4.0,>=3.8" summary = "SQLAlchemy ORM support for nonebot" groups = ["default", "extra"] @@ -1343,24 +1393,24 @@ dependencies = [ "typing-extensions~=4.9; python_version < \"3.11\"", ] files = [ - {file = "nonebot_plugin_orm-0.7.5-py3-none-any.whl", hash = "sha256:a16419950c1bf72c97c199fdc508a8380d438fa55cc129a5ca815cf8aa5411ac"}, - {file = "nonebot_plugin_orm-0.7.5.tar.gz", hash = "sha256:fe29be515bf07fa783d894d784d9e80cb26ff8f43222db88660d9e22e2e7ca24"}, + {file = "nonebot_plugin_orm-0.7.6-py3-none-any.whl", hash = "sha256:6ce808d7e847eb7c1a738609b0e94bb612488650c5150ae1b2d67463034bb255"}, + {file = "nonebot_plugin_orm-0.7.6.tar.gz", hash = "sha256:3ae4ac362a8ea6e6467666f654287855a30447f8fa457af88f1760f155c5d68c"}, ] [[package]] name = "nonebot-plugin-orm" -version = "0.7.5" +version = "0.7.6" extras = ["aiosqlite"] requires_python = "<4.0,>=3.8" summary = "SQLAlchemy ORM support for nonebot" groups = ["extra"] dependencies = [ - "nonebot-plugin-orm==0.7.5", + "nonebot-plugin-orm==0.7.6", "sqlalchemy[aiosqlite]", ] files = [ - {file = "nonebot_plugin_orm-0.7.5-py3-none-any.whl", hash = "sha256:a16419950c1bf72c97c199fdc508a8380d438fa55cc129a5ca815cf8aa5411ac"}, - {file = "nonebot_plugin_orm-0.7.5.tar.gz", hash = "sha256:fe29be515bf07fa783d894d784d9e80cb26ff8f43222db88660d9e22e2e7ca24"}, + {file = "nonebot_plugin_orm-0.7.6-py3-none-any.whl", hash = "sha256:6ce808d7e847eb7c1a738609b0e94bb612488650c5150ae1b2d67463034bb255"}, + {file = "nonebot_plugin_orm-0.7.6.tar.gz", hash = "sha256:3ae4ac362a8ea6e6467666f654287855a30447f8fa457af88f1760f155c5d68c"}, ] [[package]] @@ -1890,6 +1940,16 @@ files = [ {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, ] +[[package]] +name = "pytz" +version = "2024.1" +summary = "World timezone definitions, modern and historical" +groups = ["default"] +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -2013,7 +2073,7 @@ name = "six" version = "1.16.0" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" summary = "Python 2 and 3 compatibility utilities" -groups = ["tests"] +groups = ["default", "tests"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -2139,7 +2199,7 @@ files = [ [[package]] name = "tarina" -version = "0.5.4" +version = "0.5.5" requires_python = ">=3.8" summary = "A collection of common utils for Arclet" groups = ["default"] @@ -2147,35 +2207,35 @@ dependencies = [ "typing-extensions>=4.4.0", ] files = [ - {file = "tarina-0.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:49f20a447866ecc831acc82f09dec01f77a0ca1f89b12fa27268bccd29378449"}, - {file = "tarina-0.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5b24b5c07dc02c006d80930028e1c5f46945bf55effbeeaa426d5ac8f46eff88"}, - {file = "tarina-0.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed8fe5a1df3b32e69f99f5ae6615dc8c2e34459c7e7f828bbeadefb4ecd4fe4f"}, - {file = "tarina-0.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab6fac674c408bff3161a27473951df8994b54fff406680814079c9c0b82f804"}, - {file = "tarina-0.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfabcce37425aaf5db604ad916c9b69350174afcdb98192c6dbf1fc0cda2183f"}, - {file = "tarina-0.5.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:18900dc94388da4d322c56292cdab6a62da46d27ab5db30ed8809caab57c3502"}, - {file = "tarina-0.5.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b3f8b69949c85bb3cf5b27985961ba0c26e4359a42352f7d5870f6d455f4890"}, - {file = "tarina-0.5.4-cp310-cp310-win32.whl", hash = "sha256:8e4389a6147460b6ea6a795f21a6348190ca2fe0eb95faafb3120bb0d4de7033"}, - {file = "tarina-0.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:042bdbaac389334ab9c0851a5f1972dc9ed5c0387b4bcdee3ba1b2223aadb39f"}, - {file = "tarina-0.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:08964a6daa02d992be4b4bf2ace99c94549350195a749198f2d422221e93cc9f"}, - {file = "tarina-0.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81635455a307d65440c20645923041c8815c50dfeac046b64b64fd7840b7c30"}, - {file = "tarina-0.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f20ce1ecc06362bbfd7ca30b1dc19c3a049f69b7dc6061df95a0bf93ce627055"}, - {file = "tarina-0.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:539d239b35af0052be9cc7eeb3675c84b02a4b98c3d8ec51dbe7db2e9e5da92a"}, - {file = "tarina-0.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d8e9da2d450cdd93ac9a11af1ff02b6c9a305aa477cbada0d397c5b0b64e3"}, - {file = "tarina-0.5.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:15a2ac416e972b0318c53f20c3478d77fb770dfa9ab25ab43aa8975886ecb160"}, - {file = "tarina-0.5.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af522dc1ad30d7bcbbf9384f4f3aede3bebd7cecfc7127148ae0d12bd69b65d9"}, - {file = "tarina-0.5.4-cp311-cp311-win32.whl", hash = "sha256:781b1df4250e8f8f0b7902f3b7952135cbf43284e2cf490f57b738160d74b56f"}, - {file = "tarina-0.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:9d32bab544e7c74e56958b0ebcd430a80194492ca6e98ed2f6217708fabc4027"}, - {file = "tarina-0.5.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:95b1504e4241a28fe75fa0995ebfed1dad140381ad72541e5b69428c84d16735"}, - {file = "tarina-0.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9bbaefb3a627fcefc868d455cdc5d42297ba48369651821b04d8c8836307c39f"}, - {file = "tarina-0.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7cfec7c6a725bebb46b4e4a8ed64523c6deeae94dba1d3102b866c0247a32cdb"}, - {file = "tarina-0.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fccfd98ca925ec3597ca88f359f608f7762ad13a14dffcb17742b1e78e071306"}, - {file = "tarina-0.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bef0dfa5007f5138f48cbb9c2ef9564579def00b75caf47ebf53d32db7bf4044"}, - {file = "tarina-0.5.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8e6e2f0580d8dd956f92313ff51760df6893cd16fc009cdc2607130463d08bbb"}, - {file = "tarina-0.5.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:82f09edcf58b2e02622b173822c31c0ad5685f3e36667bd9de751f8c16b5305f"}, - {file = "tarina-0.5.4-cp312-cp312-win32.whl", hash = "sha256:b56956862d70f0383973d8413ed0fca9623e930acea0d7bf11a67c79714b869f"}, - {file = "tarina-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:3ee6dafc31cceae46634314db0b547052790015abaec433ff39fef5bf5b3f0f6"}, - {file = "tarina-0.5.4-py3-none-any.whl", hash = "sha256:1aa7d5c00e4bb6a35c5fd21bcbc536670df755922cd49bd9076a024fea191ade"}, - {file = "tarina-0.5.4.tar.gz", hash = "sha256:5d192a50d47b22ae8ca79e50ee760f171e563135eb04dc834a9b254211dbf32e"}, + {file = "tarina-0.5.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fda200701a81ed48e4303ccff10b5d680a7ad3d1772a6830f32995fe04459d6e"}, + {file = "tarina-0.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30ffe373da5f9e35179b96e233731e8a7bb83fe6bf8866753f468db53b3ed22e"}, + {file = "tarina-0.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb7474ba9f9d55dc29df9d317c12fdc870ba10582b0c5ce36550e237881c9ea6"}, + {file = "tarina-0.5.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a392ac4d4b94a9a51b7540d8194605be621a129147dc874933a524911a09c94e"}, + {file = "tarina-0.5.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cc131ecab68d7ec31a12dfb8f0ab0638729a9b866043a79b66dcf7022000652"}, + {file = "tarina-0.5.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:724a3d33ed7c48f68af7fc583aa21abff2cd1b60d0c51d3ba043683d715717f8"}, + {file = "tarina-0.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b04897665d96ebd55461c0876407c3e569008ba8efee4d4342bad47c32b64b0f"}, + {file = "tarina-0.5.5-cp310-cp310-win32.whl", hash = "sha256:f58c9eaa087af597cfd7e2885073c9dc93a3f93ba3f6957d55a9dacbcc1270ee"}, + {file = "tarina-0.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:b7dc4a5e0779fd4ee023abf445c2f801069a5861133c3ad04a5e055d5d5071fb"}, + {file = "tarina-0.5.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5ffb4ed6bd241809fd76b82bc7df857413cbc4a73a2ac8397374b79cb6e85e9b"}, + {file = "tarina-0.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f5551815a970cd22d6d609a8769eac3e8b499e54ac5283e01169727f9ce0edd0"}, + {file = "tarina-0.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4e2c18bcb1a3c59e45dc0fe39880b41d7e4fb5d742ef98a88fb4621aea9da02f"}, + {file = "tarina-0.5.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2db5c4bc285d73bec00b159dde6ec41b74d14371eb6da29d8b14a382e370567e"}, + {file = "tarina-0.5.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74923bc3d6884639e102a6a35bffda9578d934a23c4eb3f2d835e718ac75cee"}, + {file = "tarina-0.5.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e55686cff98c91ed4982226163ac5daeaf85510b4acab0c3d75331e255fbdce0"}, + {file = "tarina-0.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:50572901cd69983cfdc9d5a5823d17c49755f9e071eb287e091df014beaf6e73"}, + {file = "tarina-0.5.5-cp311-cp311-win32.whl", hash = "sha256:9d0a20f8b084af361fab7b070917edad611ede38014bab2cfc4024599586ade0"}, + {file = "tarina-0.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:8e740532d5a9346079c55613adfb77895f596a9c57e46c06d7d6c03640bd4f38"}, + {file = "tarina-0.5.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1bab4762a24d9fcd8eacae4376c8fa2d4a96e1a3c5aadbeaad9e113cd679ee7d"}, + {file = "tarina-0.5.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:05149d5aef6947fcf11a5b6cbbab788202077a734b7a2d184a574283de311725"}, + {file = "tarina-0.5.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b4ae866721d7b906fb327f847d9f8522f46bbea3b0df61b74d6bcc22dad1a33c"}, + {file = "tarina-0.5.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c687aa0cfef24b1df2c8f044a72d8993d68b4e13ea8967b79105be7a2e4097dd"}, + {file = "tarina-0.5.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e609199df957cd35cee6a942028f4caded21f1db8ac4c300c1dba94d61f0080"}, + {file = "tarina-0.5.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d57033ce9fa1c6c0a3a4851503c7320e7f7eba5dfc77e4e2f98932f1b329ba85"}, + {file = "tarina-0.5.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:986c5c59e30041e2a223c04b429777d3848c40e70b449f395b4b40290b6ff1ef"}, + {file = "tarina-0.5.5-cp312-cp312-win32.whl", hash = "sha256:256cf6a4f6a395b90aa4c1305f69a36c5fa6155124b30157a4c7e7af7c6be9ca"}, + {file = "tarina-0.5.5-cp312-cp312-win_amd64.whl", hash = "sha256:ada4a85937cb7f0c5968ffc1b4914779d35525bff14e451113da94028d6a7a23"}, + {file = "tarina-0.5.5-py3-none-any.whl", hash = "sha256:4828ace26e49037b2dab624e62ca13a473909b2f535f1b4fd5169dd01e16f6c5"}, + {file = "tarina-0.5.5.tar.gz", hash = "sha256:762a3871906e3dd79fc82d13ff99f14f1af977c4b8e2ce860209b8fa97a8b321"}, ] [[package]] @@ -2250,6 +2310,33 @@ files = [ {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 = "urllib3" version = "2.2.2" diff --git a/pyproject.toml b/pyproject.toml index 0e482b4..a2c538c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ dependencies = [ "nonebot-plugin-localstore>=0.7.1", "expiringdictx>=1.0.1", "httpx>=0.27.0", + "nonebot-plugin-argot>=0.1.1", ] requires-python = ">=3.10" readme = "README.md" diff --git a/tests/lolicon.json b/tests/lolicon.json new file mode 100644 index 0000000..91cf9b6 --- /dev/null +++ b/tests/lolicon.json @@ -0,0 +1,38 @@ +{ + "error": "", + "data": [ + { + "pid": 98332818, + "p": 0, + "uid": 3597480, + "title": "コハル", + "author": "NonDDu", + "r18": false, + "width": 1631, + "height": 2251, + "tags": [ + "ブルーアーカイブ", + "碧蓝档案", + "ブ ルアカ", + "下江コハル", + "ハイアングル", + "俯瞰", + "ピンク髪ロング", + "long pink hair", + "赤面", + "脸红", + "翼", + "羽翼", + "補習授 業部", + "Supplementary Lesson Department", + "トリニティ総合学園" + ], + "ext": "png", + "aiType": 0, + "uploadDate": 1652501854000, + "urls": { + "original": "https: //i.pixiv.re/img-original/img/2022/05/14/13/17/34/98332818_p0.png" + } + } + ] +} diff --git a/tests/test_image.jpg b/tests/test_image.jpg new file mode 100644 index 0000000..0cf3ff7 Binary files /dev/null and b/tests/test_image.jpg differ diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..36b709a --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,140 @@ +import json +import base64 +from pathlib import Path + +import httpx +import respx +import pytest +from pytest_mock import MockerFixture + + +def test_image_to_base64(): + from nonebot_plugin_wakatime.utils import image_to_base64 + + test_image_path = Path(__file__).parent / "test_image.jpg" + + result = image_to_base64(test_image_path) + + with open(test_image_path, "rb") as image_file: + base64_encoded_data = base64.b64encode(image_file.read()) + expected_base64_message = base64_encoded_data.decode("utf-8") + + expected_result = "data:image/png;base64," + expected_base64_message + + assert result == expected_result + + +@respx.mock +async def test_get_lolicon_image(): + from nonebot_plugin_wakatime.utils import get_lolicon_image + + with (Path(__file__).parent / "lolicon.json").open("r", encoding="utf8") as f: + test_lolicon = json.load(f) + + route = respx.get("https://api.lolicon.app/setu/v2").mock( + return_value=httpx.Response(200, json=test_lolicon) + ) + + lolicon_image = await get_lolicon_image() + assert route.called + assert ( + lolicon_image + == "https: //i.pixiv.re/img-original/img/2022/05/14/13/17/34/98332818_p0.png" + ) # noqa: E501 + + request = route.calls.last.request + + assert request.method == "GET" + assert request.url == "https://api.lolicon.app/setu/v2" + + +def test_parse_time(): + from nonebot_plugin_wakatime.utils import parse_time + + assert parse_time("2 hrs 30 mins 15 secs") == 2 * 3600 + 30 * 60 + 15 + + assert parse_time("4 hrs") == 4 * 3600 + + assert parse_time("45 mins") == 45 * 60 + + assert parse_time("120 secs") == 120 + + assert parse_time("10 mins 30 secs") == 10 * 60 + 30 + + assert parse_time("") == 0 + + assert parse_time("abc") == 0 + + +def test_calc_work_time_percentage(): + from nonebot_plugin_wakatime.utils import calc_work_time_percentage + + assert ( + pytest.approx(calc_work_time_percentage("8 hrs", duration="day"), 0.01) == 33.33 + ) # noqa: E501 + + assert ( + pytest.approx(calc_work_time_percentage("40 hrs", duration="week"), 0.01) == 23.81 + ) # noqa: E501 + + assert ( + pytest.approx(calc_work_time_percentage("160 hrs", duration="month"), 0.01) + == 22.22 + ) # noqa: E501 + + assert pytest.approx(calc_work_time_percentage("40 hrs"), 0.01) == 23.81 + + assert calc_work_time_percentage("0 hrs", duration="week") == 0.0 + + +async def test_get_default_background_image(mocker: MockerFixture): + from nonebot_plugin_wakatime.config import config + from nonebot_plugin_wakatime.utils import get_background_image + + mocker.patch.object(config, "background_source", "default") + + assert config.background_source == "default" + + mocked_background = mocker.patch( + "nonebot_plugin_wakatime.utils.image_to_base64", + return_value="data:image/png;base64,xxxxxx", + ) + + background = await get_background_image() + + assert background == "data:image/png;base64,xxxxxx" + + mocked_background.assert_called_once() + + +async def test_get_loliapi_background_image(mocker: MockerFixture): + from nonebot_plugin_wakatime.config import config + from nonebot_plugin_wakatime.utils import get_background_image + + mocker.patch.object(config, "background_source", "LoliAPI") + + assert config.background_source == "LoliAPI" + + background = await get_background_image() + + assert background == "https://www.loliapi.com/acg/pe/" + + +async def test_get_lolicon_background_image(mocker: MockerFixture): + from nonebot_plugin_wakatime.config import config + from nonebot_plugin_wakatime.utils import get_background_image + + mocker.patch.object(config, "background_source", "Lolicon") + + assert config.background_source == "Lolicon" + + mocker.patch( + "nonebot_plugin_wakatime.utils.get_lolicon_image", + return_value="https: //i.pixiv.re/img-original/img/2022/05/14/13/17/34/1.png", + ) + + background = await get_background_image() + + assert ( + background == "https: //i.pixiv.re/img-original/img/2022/05/14/13/17/34/1.png" + ) # noqa: E501 diff --git a/tests/test_wakatime.py b/tests/test_wakatime.py index e15cf22..f4ef8f1 100644 --- a/tests/test_wakatime.py +++ b/tests/test_wakatime.py @@ -61,21 +61,20 @@ async def test_bind_wakatime_private(app: App, mocker: MockerFixture): event = fake_v11_private_message_event(message=OneBotV11Message("/waka bind")) ctx.receive_event(bot, event) - ctx.should_call_send( - event, - OneBotV11Message( - [ - OneBotV11MS.at("2310"), - OneBotV11MS.text(f"前往该页面绑定 wakatime 账号:{auth_url}"), - OneBotV11MS.text( - "\n请再次输入当前命令,并将获取到的 code 作为参数传入完成绑定" - if not mountable - else "" - ), - ] - ), - result=True, + + message = OneBotV11Message( + [ + OneBotV11MS.at("2310"), + OneBotV11MS.text(f"前往该页面绑定 wakatime 账号:{auth_url}"), + ] ) + if not mountable: + message.append( + OneBotV11MS.text( + "请再次输入当前命令,并将获取到的 code 作为参数传入完成绑定" + ) + ) + ctx.should_call_send(event, message, result=True) ctx.should_finished() @@ -141,6 +140,10 @@ async def test_get_wakatime_info(app: App, mocker: MockerFixture): "nonebot_plugin_wakatime.render", return_value=FAKE_IMAGE, ) + mocked_wakatime_info_background = mocker.patch( + "nonebot_plugin_wakatime.get_background_image", + return_value="https://nonebot.dev/logo.png", + ) async with app.test_matcher(wakatime) as ctx: adapter = get_adapter(OneBotV11Adapter) @@ -151,6 +154,12 @@ async def test_get_wakatime_info(app: App, mocker: MockerFixture): event, OneBotV11Message(OneBotV11MS.at("2310") + OneBotV11MS.image(file=FAKE_IMAGE)), result=True, + argot={ + "name": "background", + "command": "background", + "content": "https://nonebot.dev/logo.png", + "expire": 300, + }, ) ctx.should_finished() @@ -158,3 +167,4 @@ async def test_get_wakatime_info(app: App, mocker: MockerFixture): mocked_user_stats.assert_called_once() mocked_all_time_since_today.assert_called_once() mocked_wakatime_info_image.assert_called_once() + mocked_wakatime_info_background.assert_called_once()