Compare commits

...

29 Commits

Author SHA1 Message Date
cb4c6b96f0 🔖 1.5.2 2024-09-14 05:10:32 +08:00
dependabot[bot]
25c3777c0f ⬆️ Bump playwright from 1.46.0 to 1.47.0 (#437)
Bumps [playwright](https://github.com/Microsoft/playwright-python) from 1.46.0 to 1.47.0.
- [Release notes](https://github.com/Microsoft/playwright-python/releases)
- [Commits](https://github.com/Microsoft/playwright-python/compare/v1.46.0...v1.47.0)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 21:05:13 +00:00
dependabot[bot]
193fd1da2a ⬆️ Bump ruff from 0.6.4 to 0.6.5 (#436)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.4 to 0.6.5.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.4...0.6.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 21:02:31 +00:00
dependabot[bot]
2cd609dd40 ⬆️ Bump basedpyright from 1.17.3 to 1.17.4 (#435)
Bumps [basedpyright](https://github.com/detachhead/basedpyright) from 1.17.3 to 1.17.4.
- [Release notes](https://github.com/detachhead/basedpyright/releases)
- [Commits](https://github.com/detachhead/basedpyright/compare/v1.17.3...v1.17.4)

---
updated-dependencies:
- dependency-name: basedpyright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 20:58:38 +00:00
a206098805 ️ 试图提高截图速度 2024-09-14 04:50:37 +08:00
dependabot[bot]
d493ba5f0d ⬆️ Bump yarl from 1.11.0 to 1.11.1 (#433)
Bumps [yarl](https://github.com/aio-libs/yarl) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/aio-libs/yarl/releases)
- [Changelog](https://github.com/aio-libs/yarl/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/yarl/compare/v1.11.0...v1.11.1)

---
updated-dependencies:
- dependency-name: yarl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 11:58:41 +00:00
dependabot[bot]
581d1f9674 ⬆️ Bump pandas-stubs from 2.2.2.240807 to 2.2.2.240909 (#434)
Bumps [pandas-stubs](https://github.com/pandas-dev/pandas-stubs) from 2.2.2.240807 to 2.2.2.240909.
- [Changelog](https://github.com/pandas-dev/pandas-stubs/blob/main/docs/release_procedure.md)
- [Commits](https://github.com/pandas-dev/pandas-stubs/compare/v2.2.2.240807...v2.2.2.240909)

---
updated-dependencies:
- dependency-name: pandas-stubs
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 11:54:55 +00:00
dependabot[bot]
01c99e8a8c ⬆️ Bump rich from 13.8.0 to 13.8.1 (#432)
Bumps [rich](https://github.com/Textualize/rich) from 13.8.0 to 13.8.1.
- [Release notes](https://github.com/Textualize/rich/releases)
- [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Textualize/rich/compare/v13.8.0...v13.8.1)

---
updated-dependencies:
- dependency-name: rich
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 19:51:24 +08:00
dependabot[bot]
eb3f4bea04 ⬆️ Bump yarl from 1.10.0 to 1.11.0 (#431)
Bumps [yarl](https://github.com/aio-libs/yarl) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/aio-libs/yarl/releases)
- [Changelog](https://github.com/aio-libs/yarl/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/yarl/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: yarl
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 19:38:35 +00:00
dependabot[bot]
ebbbd68b05 ⬆️ Bump basedpyright from 1.17.2 to 1.17.3 (#430)
Bumps [basedpyright](https://github.com/detachhead/basedpyright) from 1.17.2 to 1.17.3.
- [Release notes](https://github.com/detachhead/basedpyright/releases)
- [Commits](https://github.com/detachhead/basedpyright/compare/v1.17.2...v1.17.3)

---
updated-dependencies:
- dependency-name: basedpyright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-10 03:35:03 +08:00
pre-commit-ci[bot]
10e0eb815e ⬆️ auto update by pre-commit hooks (#422)
* ⬆️ auto update by pre-commit hooks

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.2 → v0.6.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.2...v0.6.4)

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-09-08 16:49:56 +08:00
dependabot[bot]
a57b04e181 ⬆️ Bump yarl from 1.9.4 to 1.10.0 (#429)
Bumps [yarl](https://github.com/aio-libs/yarl) from 1.9.4 to 1.10.0.
- [Release notes](https://github.com/aio-libs/yarl/releases)
- [Changelog](https://github.com/aio-libs/yarl/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/yarl/compare/v1.9.4...v1.10.0)

---
updated-dependencies:
- dependency-name: yarl
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-08 08:45:09 +00:00
dependabot[bot]
cc2e71f1a5 ⬆️ Bump nonebot-adapter-satori from 0.12.3 to 0.12.5 (#426)
Bumps [nonebot-adapter-satori](https://github.com/nonebot/adapter-satori) from 0.12.3 to 0.12.5.
- [Release notes](https://github.com/nonebot/adapter-satori/releases)
- [Commits](https://github.com/nonebot/adapter-satori/compare/v0.12.3...v0.12.5)

---
updated-dependencies:
- dependency-name: nonebot-adapter-satori
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-08 08:41:25 +00:00
dependabot[bot]
3384263bb2 ⬆️ Bump basedpyright from 1.17.1 to 1.17.2 (#425)
Bumps [basedpyright](https://github.com/detachhead/basedpyright) from 1.17.1 to 1.17.2.
- [Release notes](https://github.com/detachhead/basedpyright/releases)
- [Commits](https://github.com/detachhead/basedpyright/compare/v1.17.1...v1.17.2)

---
updated-dependencies:
- dependency-name: basedpyright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-08 08:37:45 +00:00
dependabot[bot]
68f210dc4f ⬆️ Bump ruff from 0.6.2 to 0.6.4 (#428)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.2 to 0.6.4.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.2...0.6.4)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-08 16:34:07 +08:00
dependabot[bot]
00a85fe3e9 ⬆️ Bump nonebot-plugin-alconna from 0.52.1 to 0.52.2 (#419)
Bumps [nonebot-plugin-alconna](https://github.com/nonebot/plugin-alconna) from 0.52.1 to 0.52.2.
- [Release notes](https://github.com/nonebot/plugin-alconna/releases)
- [Commits](https://github.com/nonebot/plugin-alconna/compare/v0.52.1...v0.52.2)

---
updated-dependencies:
- dependency-name: nonebot-plugin-alconna
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-29 17:02:45 +00:00
dependabot[bot]
a10a7584ae ⬆️ Bump nonebot-plugin-user from 0.4.2 to 0.4.3 (#418)
Bumps [nonebot-plugin-user](https://github.com/he0119/nonebot-plugin-user) from 0.4.2 to 0.4.3.
- [Release notes](https://github.com/he0119/nonebot-plugin-user/releases)
- [Changelog](https://github.com/he0119/nonebot-plugin-user/blob/main/CHANGELOG.md)
- [Commits](https://github.com/he0119/nonebot-plugin-user/compare/v0.4.2...v0.4.3)

---
updated-dependencies:
- dependency-name: nonebot-plugin-user
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-29 16:58:37 +00:00
dependabot[bot]
95aac5e321 ⬆️ Bump basedpyright from 1.17.0 to 1.17.1 (#417)
Bumps [basedpyright](https://github.com/detachhead/basedpyright) from 1.17.0 to 1.17.1.
- [Release notes](https://github.com/detachhead/basedpyright/releases)
- [Commits](https://github.com/detachhead/basedpyright/compare/v1.17.0...v1.17.1)

---
updated-dependencies:
- dependency-name: basedpyright
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 00:56:00 +08:00
89d8c938e2 👷 改成在 CI 中运行 2024-08-28 00:50:19 +08:00
84db42f1ce 👷 改用 basedpyright 2024-08-28 00:40:24 +08:00
dependabot[bot]
0a660922bb ⬆️ Bump nonebot-plugin-alconna from 0.51.4 to 0.52.1 (#411)
Bumps [nonebot-plugin-alconna](https://github.com/nonebot/plugin-alconna) from 0.51.4 to 0.52.1.
- [Release notes](https://github.com/nonebot/plugin-alconna/releases)
- [Commits](https://github.com/nonebot/plugin-alconna/compare/v0.51.4...v0.52.1)

---
updated-dependencies:
- dependency-name: nonebot-plugin-alconna
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-26 22:35:47 +00:00
dependabot[bot]
56bc98cc79 ⬆️ Bump mypy from 1.11.1 to 1.11.2 (#412)
Bumps [mypy](https://github.com/python/mypy) from 1.11.1 to 1.11.2.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.11.1...v1.11.2)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-26 22:33:40 +00:00
pre-commit-ci[bot]
be61683b51 ⬆️ auto update by pre-commit hooks (#413)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.6.1 → v0.6.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.1...v0.6.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-08-27 06:31:38 +08:00
ccd5706a95 🔖 1.5.1 2024-08-26 11:43:51 +08:00
b69240caa5 👷 添加 Pyright 类型检查 2024-08-26 11:41:03 +08:00
49d00f4d0e 添加开发依赖 pyright 2024-08-26 11:38:44 +08:00
389a850025 🐛 修复打过但是没数据的爆炸
为啥会没数据??
2024-08-26 11:38:14 +08:00
20dcc2bc3d 🔖 1.5.0 2024-08-25 23:17:32 +08:00
606dddbca2 适配新赛季 list 2024-08-25 23:16:33 +08:00
20 changed files with 1000 additions and 733 deletions

View File

@@ -4,7 +4,7 @@ on:
push: push:
jobs: jobs:
Mypy: TypeCheck:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -25,3 +25,8 @@ jobs:
shell: bash shell: bash
run: | run: |
poetry run mypy ./nonebot_plugin_tetris_stats poetry run mypy ./nonebot_plugin_tetris_stats
- name: Run BasedPyright
shell: bash
run: |
poetry run basedpyright ./nonebot_plugin_tetris_stats/

View File

@@ -7,7 +7,7 @@ ci:
autoupdate_commit_msg: ':arrow_up: auto update by pre-commit hooks' autoupdate_commit_msg: ':arrow_up: auto update by pre-commit hooks'
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.1 rev: v0.6.4
hooks: hooks:
- id: ruff - id: ruff
args: [--fix, --exit-non-zero-on-fix] args: [--fix, --exit-non-zero-on-fix]

View File

@@ -23,7 +23,7 @@ command = Subcommand(
) )
from . import bind, config, query, rank, record # noqa: E402 from . import bind, config, list, query, rank, record # noqa: E402
main_command.add(command) main_command.add(command)
@@ -31,6 +31,7 @@ __all__ = [
'alc', 'alc',
'bind', 'bind',
'config', 'config',
'list',
'query', 'query',
'rank', 'rank',
'record', 'record',

View File

@@ -1,7 +1,6 @@
from typing import Literal, overload from typing import Literal, overload
from uuid import UUID from uuid import UUID
from msgspec import to_builtins
from nonebot.compat import type_validate_json from nonebot.compat import type_validate_json
from yarl import URL from yarl import URL
@@ -87,4 +86,4 @@ async def records(
async def get(url: URL, parameter: Parameter, extra_headers: dict | None = None) -> bytes: async def get(url: URL, parameter: Parameter, extra_headers: dict | None = None) -> bytes:
return await Cache.get(url % to_builtins(parameter), extra_headers) return await Cache.get(url % parameter.to_params(), extra_headers)

View File

@@ -1,7 +1,9 @@
from datetime import datetime from datetime import datetime
from typing import Literal from typing import Literal
from pydantic import BaseModel from pydantic import BaseModel, Field
from ...typing import Prisecter
class AggregateStats(BaseModel): class AggregateStats(BaseModel):
@@ -39,11 +41,29 @@ class Garbage(BaseModel):
cleared: int cleared: int
class P(BaseModel): # what is P class P(BaseModel):
pri: float pri: float
sec: float sec: float
ter: float ter: float
def to_prisecter(self) -> Prisecter:
return Prisecter(f'{self.pri}:{self.sec}:{self.ter}')
class ArCounts(BaseModel):
bronze: int | None = Field(default=None, alias='1')
silver: int | None = Field(default=None, alias='2')
gold: int | None = Field(default=None, alias='3')
platinum: int | None = Field(default=None, alias='4')
diamond: int | None = Field(default=None, alias='5')
issued: int | None = Field(default=None, alias='100')
top3: int | None = Field(default=None, alias='t3')
top5: int | None = Field(default=None, alias='t5')
top10: int | None = Field(default=None, alias='t10')
top25: int | None = Field(default=None, alias='t25')
top50: int | None = Field(default=None, alias='t50')
top100: int | None = Field(default=None, alias='t100')
class Cache(BaseModel): class Cache(BaseModel):
status: str status: str

View File

@@ -1,10 +1,15 @@
from typing import Annotated from typing import Any
from msgspec import Meta, Struct from pydantic import BaseModel, Field
from ...typing import Prisecter
class Parameter(Struct, omit_defaults=True): class Parameter(BaseModel):
after: str | None = None after: Prisecter | None = None
before: str | None = None before: Prisecter | None = None
limit: Annotated[int, Meta(ge=1, le=100)] = 25 limit: int = Field(default=25, ge=1, le=100)
country: str | None = None country: str | None = None
def to_params(self) -> dict[str, Any]:
return self.model_dump(exclude_defaults=True)

View File

@@ -4,22 +4,7 @@ from typing import Literal
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from ...typing import Rank, ValidRank from ...typing import Rank, ValidRank
from ..base import FailedModel, P, SuccessModel from ..base import ArCounts, FailedModel, P, SuccessModel
class ArCounts(BaseModel):
bronze: int | None = Field(default=None, alias='1')
silver: int | None = Field(default=None, alias='2')
gold: int | None = Field(default=None, alias='3')
platinum: int | None = Field(default=None, alias='4')
diamond: int | None = Field(default=None, alias='5')
issued: int | None = Field(default=None, alias='100')
top3: int | None = Field(default=None, alias='t3')
top5: int | None = Field(default=None, alias='t5')
top10: int | None = Field(default=None, alias='t10')
top25: int | None = Field(default=None, alias='t25')
top50: int | None = Field(default=None, alias='t50')
top100: int | None = Field(default=None, alias='t100')
class League(BaseModel): class League(BaseModel):

View File

@@ -7,5 +7,4 @@ class User(BaseModel):
avatar_revision: int | None avatar_revision: int | None
banner_revision: int | None banner_revision: int | None
country: str | None country: str | None
verified: int | None = None
supporter: int supporter: int

View File

@@ -1,10 +1,21 @@
from functools import partial
from typing import Literal from typing import Literal
from nonebot.compat import PYDANTIC_V2
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from ...typing import Rank, S1Rank, S1ValidRank from ...typing import Rank, S1Rank, S1ValidRank
from ..base import SuccessModel from ..base import SuccessModel
if PYDANTIC_V2:
from pydantic import field_validator
custom_validator = partial(field_validator, mode='before')
else:
from pydantic import validator
custom_validator = partial(validator, pre=True, always=True) # type: ignore[assignment, arg-type]
class PastInner(BaseModel): class PastInner(BaseModel):
season: str season: str
@@ -75,6 +86,13 @@ class NeverRatedData(BaseData):
percentile: Literal[-1] percentile: Literal[-1]
percentile_rank: Literal['z'] percentile_rank: Literal['z']
@custom_validator('apm', 'pps', 'vs')
@classmethod
def _(cls, value: float | None) -> float:
if value is None:
return 0
return value
class RatedData(BaseData): class RatedData(BaseData):
gamesplayed: int gamesplayed: int

View File

@@ -3,7 +3,7 @@ from typing import Literal
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from .base import FailedModel from .base import ArCounts, FailedModel
from .base import SuccessModel as BaseSuccessModel from .base import SuccessModel as BaseSuccessModel
@@ -14,13 +14,19 @@ class Badge(BaseModel):
ts: datetime | Literal[False] | None = None ts: datetime | Literal[False] | None = None
class Discord(BaseModel): class Connection(BaseModel):
id: str id: str
username: str username: str
display_username: str
class Connections(BaseModel): class Connections(BaseModel):
discord: Discord | None = None discord: Connection | None = None
twitch: Connection | None = None
twitter: Connection | None = None
reddit: Connection | None = None
youtube: Connection | None = None
steam: Connection | None = None
class Distinguishment(BaseModel): class Distinguishment(BaseModel):
@@ -28,9 +34,9 @@ class Distinguishment(BaseModel):
class Data(BaseModel): class Data(BaseModel):
id: str = Field(..., alias='_id') id: str = Field(default=..., alias='_id')
username: str username: str
role: Literal['anon', 'user', 'bot', 'halfmod', 'mod', 'admin', 'sysop', 'banned'] role: Literal['anon', 'user', 'bot', 'halfmod', 'mod', 'admin', 'sysop', 'hidden', 'banned']
ts: datetime | None = None ts: datetime | None = None
botmaster: str | None = None botmaster: str | None = None
badges: list[Badge] badges: list[Badge]
@@ -42,7 +48,6 @@ class Data(BaseModel):
badstanding: bool | None = None badstanding: bool | None = None
supporter: bool | None = None # osk说是必有, 但实际上不是 fkosk supporter: bool | None = None # osk说是必有, 但实际上不是 fkosk
supporter_tier: int supporter_tier: int
verified: bool | None = None
avatar_revision: int | None = None avatar_revision: int | None = None
"""This user's avatar ID. Get their avatar at """This user's avatar ID. Get their avatar at
@@ -57,6 +62,9 @@ class Data(BaseModel):
connections: Connections connections: Connections
friend_count: int | None = None friend_count: int | None = None
distinguishment: Distinguishment | None = None distinguishment: Distinguishment | None = None
achievements: list[int]
ar: int
ar_counts: ArCounts
class UserInfoSuccess(BaseSuccessModel): class UserInfoSuccess(BaseSuccessModel):

View File

@@ -1,4 +1,4 @@
from typing import Literal from typing import Literal, NewType
S1ValidRank = Literal[ S1ValidRank = Literal[
'x+', 'x+',
@@ -43,3 +43,5 @@ Records = Literal[
'blitz_recent', 'blitz_recent',
'blitz_progression', 'blitz_progression',
] ]
Prisecter = NewType('Prisecter', str)

View File

@@ -0,0 +1,90 @@
from nonebot_plugin_alconna import Args, Option, Subcommand
from nonebot_plugin_alconna.uniseg import UniMessage
from nonebot_plugin_session import EventSession
from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[import-untyped]
from ...db import trigger
from ...utils.host import HostPage, get_self_netloc
from ...utils.metrics import get_metrics
from ...utils.render import render
from ...utils.render.schemas.tetrio.user.list_v2 import List, TetraLeague, User
from ...utils.screenshot import screenshot
from .. import alc
from . import command
from .api.leaderboards import by
from .api.schemas.base import P
from .api.schemas.leaderboards import Parameter
from .constant import GAME_TYPE
command.add(
Subcommand(
'list',
Option('--max-tr', Args['max_tr', float], help_text='TR的上限'),
Option('--min-tr', Args['min_tr', float], help_text='TR的下限'),
Option('--limit', Args['limit', int], help_text='查询数量'),
Option('--country', Args['country', str], help_text='国家代码'),
help_text='查询 TETR.IO 段位排行榜',
)
)
@alc.assign('TETRIO.list')
async def _(
event_session: EventSession,
max_tr: float | None = None,
min_tr: float | None = None,
limit: int | None = None,
country: str | None = None,
):
async with trigger(
session_persist_id=await get_session_persist_id(event_session),
game_platform=GAME_TYPE,
command_type='list',
command_args=[
f'{key} {value}'
for key, value in zip(
('--max-tr', '--min-tr', '--limit', '--country'), (max_tr, min_tr, limit, country), strict=True
)
if value is not None
],
):
parameter = Parameter(
# ?: 似乎是只需要 pri 至少 league 榜的返回值只有 pri
after=P(pri=max_tr, sec=0, ter=0).to_prisecter() if max_tr is not None else None,
before=P(pri=min_tr, sec=0, ter=0).to_prisecter() if min_tr is not None else None,
limit=limit or 25,
country=country,
)
league = await by('league', parameter)
async with HostPage(
await render(
'v2/tetrio/user/list',
List(
show_index=True,
users=[
User(
id=i.id,
name=i.username.upper(),
avatar=f'https://tetr.io/user-content/avatars/{i.id}.jpg',
country=i.country,
tetra_league=TetraLeague(
rank=i.league.rank,
tr=round(i.league.tr, 2),
glicko=round(i.league.glicko, 2),
rd=round(i.league.rd, 2),
decaying=i.league.decaying,
pps=(metrics := get_metrics(pps=i.league.pps, apm=i.league.apm, vs=i.league.vs)).pps,
apm=metrics.apm,
apl=metrics.apl,
vs=metrics.vs,
adpl=metrics.adpl,
),
xp=i.xp,
join_at=None,
)
for i in league.data.entries
],
),
)
) as page_hash:
await UniMessage.image(raw=await screenshot(f'http://{get_self_netloc()}/host/{page_hash}.html')).finish()

View File

@@ -209,7 +209,6 @@ async def make_query_image_v2(player: Player) -> bytes:
friend_count=user_info.data.friend_count, friend_count=user_info.data.friend_count,
supporter_tier=user_info.data.supporter_tier, supporter_tier=user_info.data.supporter_tier,
bad_standing=user_info.data.badstanding or False, bad_standing=user_info.data.badstanding or False,
verified=user_info.data.verified or False,
playtime=play_time, playtime=play_time,
join_at=user_info.data.ts, join_at=user_info.data.ts,
), ),

View File

@@ -88,9 +88,7 @@ async def get_tetra_league_data() -> None:
prisecter = P(pri=9007199254740991, sec=9007199254740991, ter=9007199254740991) # * from ch.tetr.io prisecter = P(pri=9007199254740991, sec=9007199254740991, ter=9007199254740991) # * from ch.tetr.io
results: list[BySuccessModel] = [] results: list[BySuccessModel] = []
while True: while True:
model = await limit_by( model = await limit_by('league', Parameter(after=prisecter.to_prisecter(), limit=100), x_session_id)
'league', Parameter(after=f'{prisecter.pri}:{prisecter.sec}:{prisecter.ter}', limit=100), x_session_id
)
prisecter = model.data.entries[-1].p prisecter = model.data.entries[-1].p
results.append(model) results.append(model)
if len(model.data.entries) < 100: # 分页值 # noqa: PLR2004 if len(model.data.entries) < 100: # 分页值 # noqa: PLR2004

View File

@@ -1,12 +1,14 @@
import sys import sys
from collections.abc import Callable, Coroutine
from os import environ from os import environ
from platform import system from platform import system
from re import sub from re import sub
from typing import Any, ClassVar
from nonebot import get_driver from nonebot import get_driver
from nonebot.log import logger from nonebot.log import logger
from playwright.__main__ import main from playwright.__main__ import main
from playwright.async_api import Browser, async_playwright from playwright.async_api import Browser, BrowserContext, async_playwright
driver = get_driver() driver = get_driver()
@@ -27,6 +29,7 @@ class BrowserManager:
"""浏览器管理类""" """浏览器管理类"""
_browser: Browser | None = None _browser: Browser | None = None
_contexts: ClassVar[dict[str, BrowserContext]] = {}
@classmethod @classmethod
async def init_playwright(cls) -> None: async def init_playwright(cls) -> None:
@@ -72,7 +75,11 @@ class BrowserManager:
async def _start_browser(cls) -> Browser: async def _start_browser(cls) -> Browser:
"""启动浏览器实例""" """启动浏览器实例"""
playwright = await async_playwright().start() playwright = await async_playwright().start()
cls._browser = await playwright.firefox.launch() cls._browser = await playwright.firefox.launch(
firefox_user_prefs={
'network.http.max-persistent-connections-per-server': 64,
},
)
return cls._browser return cls._browser
@classmethod @classmethod
@@ -80,8 +87,26 @@ class BrowserManager:
"""获取浏览器实例""" """获取浏览器实例"""
return cls._browser or await cls._start_browser() return cls._browser or await cls._start_browser()
@classmethod
async def get_context(
cls, context_id: str = 'default', factory: Callable[[], Coroutine[Any, Any, BrowserContext]] | None = None
) -> BrowserContext:
"""获取浏览器上下文"""
return cls._contexts.setdefault(
context_id, await factory() if factory is not None else await (await cls.get_browser()).new_context()
)
@classmethod
async def del_context(cls, context_id: str) -> None:
"""删除浏览器上下文"""
if context_id in cls._contexts:
await cls._contexts[context_id].close()
del cls._contexts[context_id]
@classmethod @classmethod
async def close_browser(cls) -> None: async def close_browser(cls) -> None:
"""关闭浏览器实例""" """关闭浏览器实例"""
for i in cls._contexts.values():
await i.close()
if isinstance(cls._browser, Browser): if isinstance(cls._browser, Browser):
await cls._browser.close() await cls._browser.close()

View File

@@ -21,7 +21,7 @@ class User(BaseModel):
name: str name: str
country: str | None country: str | None
role: Literal['anon', 'user', 'bot', 'halfmod', 'mod', 'admin', 'sysop', 'banned'] role: Literal['anon', 'user', 'bot', 'halfmod', 'mod', 'admin', 'sysop', 'hidden', 'banned']
avatar: str | Avatar avatar: str | Avatar
banner: str | None banner: str | None
@@ -31,7 +31,6 @@ class User(BaseModel):
friend_count: int | None friend_count: int | None
supporter_tier: int supporter_tier: int
verified: bool
bad_standing: bool bad_standing: bool
badges: list[Badge] badges: list[Badge]

View File

@@ -26,7 +26,6 @@ class User(BaseModel):
name: str name: str
avatar: str | Avatar avatar: str | Avatar
country: str | None country: str | None
verified: bool
tetra_league: TetraLeague tetra_league: TetraLeague
xp: Number xp: Number
join_at: datetime | None join_at: datetime | None

View File

@@ -1,4 +1,4 @@
from playwright.async_api import TimeoutError, ViewportSize from playwright.async_api import BrowserContext, TimeoutError, ViewportSize
from ..config.config import config from ..config.config import config
from .browser import BrowserManager from .browser import BrowserManager
@@ -6,13 +6,15 @@ from .retry import retry
from .time_it import time_it from .time_it import time_it
async def context_factory() -> BrowserContext:
return await (await BrowserManager.get_browser()).new_context(device_scale_factor=config.tetris.screenshot_quality)
@retry(exception_type=TimeoutError, reply='截图失败, 重试中') @retry(exception_type=TimeoutError, reply='截图失败, 重试中')
@time_it @time_it
async def screenshot(url: str) -> bytes: async def screenshot(url: str) -> bytes:
browser = await BrowserManager.get_browser() context = await BrowserManager.get_context('screenshot', factory=context_factory)
async with ( async with await context.new_page() as page:
await browser.new_page(device_scale_factor=config.tetris.screenshot_quality) as page,
):
await page.goto(url) await page.goto(url)
size: ViewportSize = await page.evaluate(""" size: ViewportSize = await page.evaluate("""
() => { () => {

1466
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = 'nonebot-plugin-tetris-stats' name = 'nonebot-plugin-tetris-stats'
version = '1.4.18' version = '1.5.2'
description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件' description = '一款基于 NoneBot2 的用于查询 Tetris 相关游戏数据的插件'
authors = ['scdhh <wallfjjd@gmail.com>'] authors = ['scdhh <wallfjjd@gmail.com>']
readme = 'README.md' readme = 'README.md'
@@ -34,13 +34,14 @@ yarl = "^1.9.4"
zstandard = '>=0.22,<0.24' zstandard = '>=0.22,<0.24'
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
basedpyright = "^1.17.0"
mypy = '>=1.9' mypy = '>=1.9'
pandas-stubs = '>=1.5.2,<3.0.0'
ruff = '>=0.3.0' ruff = '>=0.3.0'
types-aiofiles = '>=23.2.0.20240106,<25.0.0.0' types-aiofiles = '>=23.2.0.20240106,<25.0.0.0'
types-lxml = '^2024.2.9' types-lxml = '^2024.2.9'
types-pillow = '^10.2.0.20240423' types-pillow = '^10.2.0.20240423'
types-ujson = '^5.9.0' types-ujson = '^5.9.0'
pandas-stubs = '>=1.5.2,<3.0.0'
nonebot2 = { extras = ['all'], version = '^2.3.0' } nonebot2 = { extras = ['all'], version = '^2.3.0' }
nonebot-adapter-discord = '^0.1.3' nonebot-adapter-discord = '^0.1.3'
nonebot-adapter-kaiheila = '^0.3.4' nonebot-adapter-kaiheila = '^0.3.4'
@@ -134,5 +135,11 @@ builtins-ignorelist = ['id']
[tool.ruff.format] [tool.ruff.format]
quote-style = 'single' quote-style = 'single'
[tool.basedpyright]
pythonVersion = "3.10"
pythonPlatform = "All"
defineConstant = { PYDANTIC_V2 = true }
typeCheckingMode = "standard"
[tool.nonebot] [tool.nonebot]
plugins = ['nonebot_plugin_tetris_stats'] plugins = ['nonebot_plugin_tetris_stats']