Compare commits
250 Commits
Author | SHA1 | Date | |
---|---|---|---|
1ae45808fd | |||
800dbbba43 | |||
c627c07aa1 | |||
4a9259dad4 | |||
|
fc017c8255 | ||
|
908812a3d9 | ||
6c7d073cb1 | |||
8677286bd4 | |||
232ffcf714 | |||
6871bc0d22 | |||
641c16ee7a | |||
75c67bdffc | |||
3a60450358 | |||
7b97210a31 | |||
d97145ee5e | |||
bc3a4355c3 | |||
d835a32683 | |||
aedea1acb9 | |||
3bce8325c1 | |||
d1c1320963 | |||
317e07eb71 | |||
37749ae15e | |||
f94c10de61 | |||
5ccef735be | |||
262002b49a | |||
40c6ba6d9e | |||
60093b562b | |||
30880ec13b | |||
cc1d82312a | |||
efca13d397 | |||
3a8c09d6db | |||
cc1bb8e5e4 | |||
93c17b6026 | |||
fd3f6272f1 | |||
4d87a3c0b7 | |||
86f47ee411 | |||
1d6b8d60f3 | |||
3890704045 | |||
b0761e9873 | |||
291314de93 | |||
fd835e9406 | |||
d681c5645a | |||
d0619f1fe8 | |||
b022a364e3 | |||
df00c61dd8 | |||
94a021bab0 | |||
6b20e9eae0 | |||
0a35a3c6f8 | |||
2e75c7bc65 | |||
3341505715 | |||
bdde9c45fd | |||
7bf94a15c8 | |||
4510477026 | |||
86e50e369b | |||
796fc6f233 | |||
|
80c6875567 | ||
ab89cd1c72 | |||
5e454bc971 | |||
70bfb0fcee | |||
13b95c2732 | |||
ef5866343d | |||
d5ccd105a2 | |||
20ad8dc53f | |||
de9c91d8bd | |||
6b64a0c379 | |||
f117da7ff3 | |||
f548a07230 | |||
e2e53c21fa | |||
3eaf23a56b | |||
4a5dd1f727 | |||
c2cb416b4e | |||
5cd528d5e9 | |||
980fca650b | |||
9c525141f6 | |||
3d218a0e8d | |||
db385f597b | |||
98a9d6413a | |||
a77f97fd4b | |||
e6ea1b700f | |||
596f4d06ea | |||
8e3d3b3b5d | |||
a34ad87e01 | |||
6c4c7f34cd | |||
0c859957b4 | |||
fbb9ed82ee | |||
b469c9420e | |||
aa4d930cc4 | |||
76be748160 | |||
a9dd37b8a5 | |||
5900d621f2 | |||
7442a3651b | |||
413f438689 | |||
1fc4999b09 | |||
975446a096 | |||
98cdd2f4b8 | |||
c0beec0429 | |||
614d78b3fa | |||
24b0f345e4 | |||
0ae10aa1b2 | |||
9fe7478840 | |||
|
efca0bc7b3 | ||
50c5e99b98 | |||
7415efcc90 | |||
5bb4584e6a | |||
795a6f3f76 | |||
|
fa74e08514 | ||
e6cf6e0c68 | |||
6789c16773 | |||
cdea0f8563 | |||
9df55671ac | |||
d96c6f13c1 | |||
bce1bf8704 | |||
8eb626b8da | |||
|
e6505d335b | ||
c8cb341afb | |||
e99cb88b13 | |||
|
78c3e299d0 | ||
23338437e9 | |||
f95899aebd | |||
5df10c66b6 | |||
811d1594cd | |||
c162208638 | |||
679d6597d8 | |||
f402799f28 | |||
|
60542d7426 | ||
db1fb58717 | |||
7d5675ec97 | |||
d8c50752f7 | |||
|
c674b837bb | ||
d867996072 | |||
7ef36c6933 | |||
982aae4dbf | |||
b5d3c6aaa8 | |||
5537bc32df | |||
5c0c723c5d | |||
0ed3b307d9 | |||
53a603d4ee | |||
fbf906bea7 | |||
a87e8bc3e8 | |||
a16a67dbc9 | |||
4c2231feb5 | |||
3932dd60da | |||
3c6380cb82 | |||
2612f99f35 | |||
0b4b9a6241 | |||
2d100885ee | |||
cb335720b7 | |||
dc8ad30b84 | |||
09e00652c3 | |||
b5b15c82f8 | |||
72e71124b8 | |||
d2be2acc95 | |||
d95614e960 | |||
dad9482d7a | |||
fff5d09ad9 | |||
e6ffd1fcc0 | |||
a97747b7c4 | |||
1921dcd023 | |||
18af1d00bd | |||
30cdc1da23 | |||
|
bb84958ce4 | ||
|
44de3fd00a | ||
39b1920532 | |||
aa591ec29e | |||
310c3f065d | |||
2311ef82c3 | |||
b4b931fc95 | |||
d1b887fcaa | |||
5a2990770c | |||
1d0f0a2539 | |||
dbc4d83b08 | |||
da905d21bd | |||
7d91079500 | |||
81a006a308 | |||
be59e241c6 | |||
e493139d85 | |||
1f59ec2ef9 | |||
20d05f609d | |||
0f9683de89 | |||
c805db3371 | |||
58d0d12c1f | |||
359683dbae | |||
94cab8b743 | |||
837447b6e4 | |||
ad52eade07 | |||
9cae3edb6b | |||
0860b61ccd | |||
d125c52b50 | |||
d485e095ae | |||
499caca7e3 | |||
83a2d36209 | |||
8b77ced05e | |||
49a9617f08 | |||
06aa919d9b | |||
77b77c285b | |||
bdc32b26fe | |||
736125f4ee | |||
89cb75f105 | |||
34a6261f27 | |||
ae18bfaee1 | |||
8510b0ed3f | |||
967f1a0e5b | |||
6c1fc62ef1 | |||
433c6b3b85 | |||
ee1ae5a071 | |||
49a15d512e | |||
fd1d73cc32 | |||
29c2aa9404 | |||
0ec1195930 | |||
d7a625bedb | |||
3854376210 | |||
5253d0e515 | |||
|
3bc7fa82b1 | ||
7d98d5819d | |||
8316c0ff63 | |||
315b8c91e5 | |||
|
405eb10a8a | ||
c3072e93c7 | |||
ae34ff622d | |||
d2704818d9 | |||
2ab4184314 | |||
9aade6599c | |||
2f87b06c83 | |||
8bb3f15bd9 | |||
7f198c83b5 | |||
f70c75e9c4 | |||
be5a4b270d | |||
50c0216435 | |||
4910de74fd | |||
f12b6854b7 | |||
b0b61fbaf7 | |||
7c0b0df6ed | |||
cb3ee4b72f | |||
3a3ef4d6ae | |||
|
9b3dea840e | ||
ca89fa7efd | |||
4705eac79c | |||
ebe0c5bcbb | |||
93c287bbd9 | |||
0defb00ede | |||
81c1d0286d | |||
fb25005bd5 | |||
2eb5aae23f | |||
a7d0560932 | |||
391f112bb3 | |||
bc8d13ba8a | |||
e8ec2ee28a | |||
b6c8fcbccd | |||
71476560e4 | |||
aa2d182840 |
0
.dockerignore
Normal file → Executable file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Executable file
@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
59
.github/ISSUE_TEMPLATE/resource_publish_en.yml
vendored
Executable file
@ -0,0 +1,59 @@
|
||||
name: Publish Resource
|
||||
title: "Resource: {name}"
|
||||
description: Publish the resource to the LiteyukiBot official store
|
||||
labels: [ "Resource" ]
|
||||
body:
|
||||
- type: input
|
||||
id: name
|
||||
attributes:
|
||||
label: Name
|
||||
description: The readable name of the resource pack
|
||||
placeholder: e.g. Cute UI Resource Pack
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: A brief description of the resource
|
||||
placeholder: e.g. Makes the rendering card style more beautiful
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: author
|
||||
attributes:
|
||||
label: Author
|
||||
description: The GitHub username of the author
|
||||
placeholder: e.g. snowykami
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: link
|
||||
attributes:
|
||||
label: Link
|
||||
description: Direct download link of the resource pack
|
||||
placeholder: e.g. https://aaa.com/r.zip
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: homepage
|
||||
attributes:
|
||||
label: Homepage
|
||||
description: Homepage of the resource pack
|
||||
placeholder: e.g. https://github.com/user/repo
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: tags
|
||||
attributes:
|
||||
label: Tags
|
||||
description: Tags
|
||||
placeholder: 'e.g. [{"label": "Tag Name", "color": "#ea5252"}]'
|
||||
value: '[ { "label": "Text", "color": "#a2d8f4" } ]'
|
||||
validations:
|
||||
required: false
|
59
.github/ISSUE_TEMPLATE/resource_publish_zh.yml
vendored
Executable file
@ -0,0 +1,59 @@
|
||||
name: 发布资源
|
||||
title: "Resource: {name}"
|
||||
description: 发布资源到轻雪机器人官方商店
|
||||
labels: [ "Resource" ]
|
||||
body:
|
||||
- type: input
|
||||
id: name
|
||||
attributes:
|
||||
label: 名称
|
||||
description: 资源包的可读名称
|
||||
placeholder: e.g. 可爱UI资源包
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: description
|
||||
attributes:
|
||||
label: 描述
|
||||
description: 资源的简短描述
|
||||
placeholder: e.g. 使渲染卡片的样式更美观
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: author
|
||||
attributes:
|
||||
label: 作者
|
||||
description: 作者的github用户名
|
||||
placeholder: e.g. snowykami
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: link
|
||||
attributes:
|
||||
label: 下载链接
|
||||
description: 资源包直接下载链接
|
||||
placeholder: e.g. https://aaa.com/r.zip
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: homepage
|
||||
attributes:
|
||||
label: 主页
|
||||
description: 资源包主页
|
||||
placeholder: e.g. https://github.com/user/repo
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: tags
|
||||
attributes:
|
||||
label: 标签
|
||||
description: 标签
|
||||
placeholder: 'e.g. [{"label": "标签名", "color": "#ea5252"}]'
|
||||
value: '[ { "label": "标签名", "color": "#a2d8f4" } ]'
|
||||
validations:
|
||||
required: false
|
0
.github/ISSUE_TEMPLATE/问题反馈.md
vendored
Normal file → Executable file
0
.github/dependabot.yml
vendored
Normal file → Executable file
44
.github/workflows/ISSUE_TEMPLATE.md
vendored
@ -1,44 +0,0 @@
|
||||
# 问题反馈
|
||||
|
||||
## **请确保**
|
||||
|
||||
- 已认真阅读[文档]("https://bot.liteyuki.icu"),该问题不是文档提及的或你自己操作不当造成的
|
||||
- 你的问题是在最新版本的代码上测试的
|
||||
- 请勿重复提交相同或类似的issue
|
||||
|
||||
|
||||
## **描述问题**
|
||||
|
||||
请在此简单描述问题
|
||||
|
||||
|
||||
|
||||
## **如何复现**
|
||||
|
||||
请阐述一下如何重现这个问题
|
||||
### 预期
|
||||
|
||||
描述你期望发生的事情
|
||||
|
||||
### 实际
|
||||
|
||||
描述实际发生的事情
|
||||
|
||||
|
||||
|
||||
## **日志或截图**
|
||||
```
|
||||
日志内容
|
||||
```
|
||||
|
||||
|
||||
## **设备信息**
|
||||
- **系统**: [例如 Ubuntu 22.04]
|
||||
- **CPU**: [例如 Intel i7-7700K]
|
||||
- **内存**: [例如 16GB]
|
||||
- **Python**: [例如CPython 3.10.7]
|
||||
|
||||
|
||||
**补充内容**
|
||||
|
||||
可选,推荐提供`pip freeze`的输出,以及其他相关信息,以及你的建议
|
43
.github/workflows/build-image.yml
vendored
Executable file
@ -0,0 +1,43 @@
|
||||
|
||||
name: Docker Image Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: docker-build
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USERNAME }}
|
||||
password: ${{ secrets.GHCR_PASSWORD }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/liteyukistudio/liteyukibot:latest
|
||||
|
||||
- name: Log out from GitHub Container Registry
|
||||
run: docker logout ghcr.io
|
66
.github/workflows/deploy-docs-liteyukicloud.yml
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
name: Deploy VitePress site to Liteyuki PaaS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: write
|
||||
statuses: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
MELI_SITE: "800a7c09-dd9c-4ba7-a43f-af9bc69808c4"
|
||||
|
||||
jobs:
|
||||
# 构建工作
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 如果未启用 lastUpdated,则不需要
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Setup API markdown
|
||||
run: |-
|
||||
python -m pip install litedoc
|
||||
litedoc liteyuki -o docs/zh/dev/api -l zh-Hans -cd class -fd func -md func -vd var -bu https://github.com/LiteyukiStudio/LiteyukiBot/tree/main/liteyuki/
|
||||
litedoc liteyuki -o docs/en/dev/api -l en -cd class -fd func -md func -vd var -bu https://github.com/LiteyukiStudio/LiteyukiBot/tree/main/liteyuki/
|
||||
|
||||
- name: 安装 pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
run_install: true
|
||||
version: 8
|
||||
|
||||
- name: 设置 Node.js
|
||||
run: |-
|
||||
cd docs
|
||||
pnpm install
|
||||
|
||||
- name: 构建文档
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
run: |-
|
||||
cd docs
|
||||
pnpm run docs:build
|
||||
> .vitepress/dist/.nojekyll
|
||||
|
||||
- name: "发布"
|
||||
run: |
|
||||
npx -p "@getmeli/cli" meli upload docs/.vitepress/dist \
|
||||
--url "https://dash.apage.dev" \
|
||||
--site "$MELI_SITE" \
|
||||
--token "$MELI_TOKEN" \
|
||||
--release "$GITHUB_SHA"
|
||||
env:
|
||||
MELI_TOKEN: ${{ secrets.MELI_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
61
.github/workflows/deploy-docs.yml
vendored
@ -1,61 +0,0 @@
|
||||
|
||||
name: 部署文档
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
# 确保这是你正在使用的分支名称
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
deploy-gh-pages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# 如果你文档需要 Git 子模块,取消注释下一行
|
||||
# submodules: true
|
||||
|
||||
- name: 安装 pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
run_install: true
|
||||
version: 8
|
||||
|
||||
|
||||
- name: 设置 Node.js
|
||||
run: |-
|
||||
cd docs
|
||||
pnpm install
|
||||
|
||||
- name: 设置Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
|
||||
- name: 生成API markdown
|
||||
run: |-
|
||||
python -m pip install pydantic
|
||||
python liteyuki/mkdoc.py
|
||||
|
||||
|
||||
- name: 构建文档
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=8192
|
||||
run: |-
|
||||
cd docs
|
||||
pnpm run docs:build
|
||||
> .vuepress/dist/.nojekyll
|
||||
|
||||
- name: 部署文档
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
# 这是文档部署到的分支名称
|
||||
branch: gh-pages
|
||||
folder: docs/.vuepress/dist
|
51
.github/workflows/issue_handler.yml
vendored
Executable file
@ -0,0 +1,51 @@
|
||||
name: Issue Handler
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [ opened, edited, closed ]
|
||||
|
||||
concurrency:
|
||||
group: issue_handler
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
check-issue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Check issue title
|
||||
id: check_title
|
||||
run: |
|
||||
ISSUE_TITLE="${{ github.event.issue.title }}"
|
||||
if [[ "$ISSUE_TITLE" == Plugin:* || "$ISSUE_TITLE" == Resource:* ]]; then
|
||||
echo "Title starts with Plugin: or Resource:."
|
||||
echo "::set-output name=title_match::true"
|
||||
else
|
||||
echo "Title does not start with Plugin: or Resource:."
|
||||
echo "::set-output name=title_match::false"
|
||||
fi
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
if: steps.check_title.outputs.title_match == 'true'
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.check_title.outputs.title_match == 'true'
|
||||
run: |
|
||||
echo "Installing dependencies."
|
||||
pip install -r liteyuki_flow/requirements.txt
|
||||
|
||||
- name: Run Plugin/Resource issue handler
|
||||
if: steps.check_title.outputs.title_match == 'true'
|
||||
run: |
|
||||
echo "Running Plugin/Resource issue handler."
|
||||
python -m liteyuki_flow --handle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
ACT_TYPE: ${{ github.event.action }}
|
30
.github/workflows/pre-commit.yml
vendored
Executable file
@ -0,0 +1,30 @@
|
||||
name: Pre-commit checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13'] # 添加你想要测试的 Python 版本
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }} # 使用矩阵中的 Python 版本
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install pdm
|
||||
python -m pip install pre-commit
|
||||
pdm config python.use_venv false
|
||||
pdm install --no-lock
|
||||
pre-commit install
|
||||
|
||||
- name: Run pre-commit
|
||||
run: pre-commit run --all-files
|
5
.github/workflows/pypi-publish.yml
vendored
Normal file → Executable file
@ -1,8 +1,9 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
pypi-publish:
|
||||
|
23
.gitignore
vendored
Normal file → Executable file
@ -17,14 +17,13 @@ __pycache__/
|
||||
/plugins/
|
||||
|
||||
#config
|
||||
config/
|
||||
/config/
|
||||
!config/default.yml
|
||||
_config.yml
|
||||
config.yml
|
||||
config.example.yml
|
||||
|
||||
# vuepress
|
||||
.github
|
||||
|
||||
# mupy
|
||||
mypy.ini
|
||||
@ -54,4 +53,22 @@ dist
|
||||
doc
|
||||
|
||||
mkdoc2.py
|
||||
result.json
|
||||
result.json
|
||||
|
||||
# litedoc
|
||||
docs/zh/dev/api
|
||||
docs/en/dev/api
|
||||
mkdoc.bat
|
||||
|
||||
# vitepress
|
||||
docs/.vitepress/dist/
|
||||
docs/.vitepress/cache
|
||||
docs/.vitepress/.temp
|
||||
|
||||
# python toolchain
|
||||
.mypy_cache/
|
||||
.pytest_cache/
|
||||
|
||||
# pdm
|
||||
__pypackages__/
|
||||
pdm.lock
|
26
.pre-commit-config.yaml
Executable file
@ -0,0 +1,26 @@
|
||||
fail_fast: true
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 24.4.2
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--config=./pyproject.toml]
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
args: ["--profile", "black"]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.13.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
6
Dockerfile
Normal file → Executable file
@ -2,17 +2,15 @@ FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.10-slim
|
||||
|
||||
ENV TZ Asia/Shanghai
|
||||
|
||||
COPY docker/sources.list /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y git
|
||||
|
||||
WORKDIR /liteyukibot
|
||||
|
||||
COPY . /liteyukibot
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
RUN apt-get install -y libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libasound2
|
||||
RUN apt-get install -y libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libasound2 libpango-1.0-0 libcairo2
|
||||
|
||||
EXPOSE 20216
|
||||
|
||||
|
60
README.md
Normal file → Executable file
@ -1,52 +1,70 @@
|
||||
<div align="center">
|
||||
|
||||
[//]: # (<img src="https://cdn.liteyuki.icu/static/svg/lylogo-full.svg" style="align-content: center; width: 50%; margin-top:10%;" alt="a">)
|
||||
[![][banner]][lightyuki-link]
|
||||
[//]: # (<img src="https://cdn.liteyuki.icu/logos/bot.svg" style="align-content: center; width: 50%; margin-top:10%;" alt="a">)
|
||||
[![][banner]][liteyuki-link]
|
||||
<h2><a href="https://bot.liteyuki.icu"> <span style="color: #a2d8f4">轻雪</span> <span style="color: #d0e9ff">6</span></a></h2>
|
||||
<h4> <span style="color: #a2d8f4">✨ 轻量,高效,易于扩展✨</span></h4>
|
||||
|
||||
[![][OneBot]][onebot-link]
|
||||
[![][NoneBot2]][nonebot-link]
|
||||
[![][Liteyuki6.0]][lightyuki-link]
|
||||
[![][Liteyuki6.0]][liteyuki-link]
|
||||
[![][Python3.10+]][python-link]
|
||||
[![][Usage]][usage-link]
|
||||
[![][Repo]][repo-link]
|
||||
[![][Github]][github-link]
|
||||
[![][LiteyukiLab]][liteyukilab-link]
|
||||

|
||||
|
||||
- 基于[Nonebot2](https://github.com/nonebot/nonebot2),有良好的生态支持
|
||||
</div>
|
||||
|
||||
## 关于
|
||||
|
||||
访问[轻雪6.0](https://bot.liteyuki.icu)主页获取更多信息
|
||||
|
||||
## 特点及优势
|
||||
|
||||
- 原生支持与任意`Python`Bot框架互联,有良好的生态支持
|
||||
- 开箱即用,无需复杂配置
|
||||
- 集成包管理器,支持一键安装插件
|
||||
- 支持OneBot标准通信但不限于此
|
||||
- 自定义主题支持,满足审美需求
|
||||
- 国际化支持,支持多种语言
|
||||
- 高性能,500插件2s内启动
|
||||
|
||||
<h3>👇更多内容请访问👇</h3>
|
||||
<h2><a href="https://bot.liteyuki.icu">轻雪机器人主页</a></h2>
|
||||
</div>
|
||||
## 服务及支持(敬请期待)
|
||||
- 提供Liteyuki Cloud官方的容器化托管服务,无需担心服务器问题
|
||||
|
||||
### 感谢
|
||||
- [NoneBot2](https://nonebot.dev)提供的框架支持
|
||||
- [nonebot-plugin-htmlrender](https://github.com/kexue-z/nonebot-plugin-htmlrender)提供的渲染功能
|
||||
- [nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna)提供的命令解析功能
|
||||
**👇所有内容请访问👇**: [bot.liteyuki.icu](https://bot.liteyuki.icu)
|
||||
|
||||
## 参考及鸣谢
|
||||
- [nonebot-plugin-uninfo](https://github.com/RF-Tar-Railt/nonebot-plugin-uninfo)为会话部分用户信息提供了参考
|
||||
- [nonebot-plugin-alconna](https://github.com/nonebot/plugin-alconna/)为消息部分提供了参考
|
||||
|
||||
[OneBot]: https://img.shields.io/badge/OneBot-11/12-blue?style=for-the-badge
|
||||
## 其他
|
||||
- 本仓库是一个monorepo,包含了框架,文档,测试,内置资源包,内置插件,预设配置等
|
||||
|
||||
[NoneBot2]: https://img.shields.io/badge/Nonebot-2-red?style=for-the-badge
|
||||
|
||||
[Liteyuki6.0]: https://img.shields.io/badge/Liteyuki-6.0-blue?style=for-the-badge
|
||||
|
||||
[Python3.10+]: https://img.shields.io/badge/Python-3.10+-blue?style=for-the-badge
|
||||
|
||||
[Usage]: https://img.shields.io/badge/文档-页面-blue?style=for-the-badge
|
||||
[Usage]: https://img.shields.io/badge/主页-文档-blue?style=for-the-badge
|
||||
|
||||
[onebot-link]:https://onebot.dev/
|
||||
[Repo]: https://img.shields.io/badge/官方托管-仓库-blue?style=for-the-badge
|
||||
|
||||
[Github]: https://img.shields.io/badge/Github-仓库-blue?style=for-the-badge
|
||||
|
||||
[LiteyukiLab]: https://img.shields.io/badge/轻雪社区-官方-blue?style=for-the-badge
|
||||
|
||||
[nonebot-link]:https://nonebot.dev/
|
||||
|
||||
[lightyuki-link]:/
|
||||
|
||||
[python-link]:https://www.python.org/
|
||||
|
||||
[usage-link]:https://bot.liteyuki.icu/
|
||||
|
||||
[banner]: https://socialify.git.ci/LiteyukiStudio/LiteyukiBot/image?description=1&forks=1&issues=1&Plus&pulls=1&stargazers=1&theme=Auto&logo=https%3a%2f%2fcdn.liteyuki.icu%2fstatic%2fsvg%2flylogo-full.svg
|
||||
[liteyuki-link]:https://bot.liteyuki.icu/
|
||||
|
||||
[repo-link]:https://git.liteyuki.icu/bot/app
|
||||
|
||||
[github-link]:https://github.com/LiteyukiStudio/LiteyukiBot
|
||||
|
||||
[liteyukilab-link]:https://lab.liteyuki.icu/@LiteyukiBot
|
||||
|
||||
[banner]: https://socialify.git.ci/LiteyukiStudio/LiteyukiBot/image?description=1&font=Source+Code+Pro&forks=1&issues=1&logo=https%3A%2F%2Fcdn.liteyuki.icu%2Flogos%2Fbot.svg&name=1&owner=1&pattern=Floating+Cogs&pulls=1&stargazers=1&theme=Auto
|
||||
|
6
config/default.yml
Normal file → Executable file
@ -1,8 +1,10 @@
|
||||
nonebot:
|
||||
host: 127.0.0.1
|
||||
host: 0.0.0.0
|
||||
port: 20216
|
||||
command_start: ["", "/"]
|
||||
nickname: [ "liteyuki" ]
|
||||
default_language: zh
|
||||
driver: ~fastapi+~httpx+~websockets
|
||||
alconna_use_command_start: true
|
||||
alconna_use_command_start: true
|
||||
gotify_token: "empty token"
|
||||
|
||||
|
12
docker-compose.yml
Executable file
@ -0,0 +1,12 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
image: git.liteyuki.icu/bot/app:latest
|
||||
ports:
|
||||
- "20216:20216"
|
||||
environment:
|
||||
- TZ=Asia/Chongqing
|
||||
volumes:
|
||||
- .:/liteyukibot
|
||||
command: [ "python", "main.py" ]
|
0
docker/sources.list
Normal file → Executable file
5
docs/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
|
||||
node_modules/
|
||||
./.vuepress/.cache/
|
||||
./.vuepress/.temp/
|
||||
./.vuepress/dist/
|
138
docs/.vitepress/config/common.ts
Executable file
@ -0,0 +1,138 @@
|
||||
// 共有配置项,导入index用
|
||||
|
||||
import { defineConfig } from "vitepress";
|
||||
import { generateSidebar } from "vitepress-sidebar";
|
||||
import { zh } from "./zh";
|
||||
import { en } from "./en";
|
||||
|
||||
let defaultLocale = "zh";
|
||||
const commonSidebarOptions = {
|
||||
collapsed: true,
|
||||
convertSameNameSubFileToGroupIndexPage: true,
|
||||
useTitleFromFrontmatter: true,
|
||||
useFolderTitleFromIndexFile: true,
|
||||
useFolderLinkFromIndexFile: true,
|
||||
includeFolderIndexFile: true,
|
||||
sortMenusByFrontmatterOrder: true,
|
||||
rootGroupText: "LITEYUKIBOT",
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate sidebar config
|
||||
* multiple languages and sections
|
||||
* @returns {any[]}
|
||||
*/
|
||||
function generateSidebarConfig(): any[] {
|
||||
let sections = ["dev", "store", "usage", "deploy"];
|
||||
let languages = ["zh", "en"];
|
||||
let ret = [];
|
||||
for (let language of languages) {
|
||||
for (let section of sections) {
|
||||
if (language === defaultLocale) {
|
||||
ret.push({
|
||||
basePath: `/${section}/`,
|
||||
scanStartPath: `${language}/${section}`,
|
||||
resolvePath: `/${section}/`,
|
||||
...commonSidebarOptions,
|
||||
});
|
||||
} else {
|
||||
ret.push({
|
||||
basePath: `/${language}/${section}/`,
|
||||
scanStartPath: `${language}/${section}`,
|
||||
resolvePath: `/${language}/${section}/`,
|
||||
...commonSidebarOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
export const common = defineConfig({
|
||||
head: [
|
||||
// 配置favicon.ico
|
||||
["link", { rel: "icon", type: "image/x-icon", href: "favicon.ico" }],
|
||||
[
|
||||
"link",
|
||||
{
|
||||
rel: "stylesheet",
|
||||
href: "https://fonts.font.im/css?family=Cousine:400,400i,700,700i|Poppins:100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i",
|
||||
},
|
||||
],
|
||||
["script", { src: "https://cdn.liteyuki.icu/js/liteyuki_footer.js" }],
|
||||
],
|
||||
rewrites: {
|
||||
[`${defaultLocale}/:rest*`]: ":rest*",
|
||||
},
|
||||
cleanUrls: false,
|
||||
themeConfig: {
|
||||
logo: {
|
||||
light: "https://cdn.liteyuki.icu/logos/bot.svg",
|
||||
dark: "https://cdn.liteyuki.icu/logos/bot.svg",
|
||||
alt: "LiteyukiBot Logo",
|
||||
},
|
||||
sidebar: generateSidebar([...generateSidebarConfig()]),
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://github.com/LiteyukiStudio/LiteyukiBot" },
|
||||
{
|
||||
icon: {
|
||||
svg: '<svg t="1725391346807" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5067" width="256" height="256"><path d="M1004.692673 466.396616l-447.094409-447.073929c-25.743103-25.763582-67.501405-25.763582-93.264987 0l-103.873521 103.873521 78.171378 78.171378c12.533635-6.00058 26.562294-9.359266 41.389666-9.359266 53.02219 0 96.00928 42.98709 96.00928 96.00928 0 14.827372-3.358686 28.856031-9.359266 41.389666l127.97824 127.97824c12.533635-6.00058 26.562294-9.359266 41.389666-9.359266 53.02219 0 96.00928 42.98709 96.00928 96.00928s-42.98709 96.00928-96.00928 96.00928-96.00928-42.98709-96.00928-96.00928c0-14.827372 3.358686-28.856031 9.359266-41.389666l-127.97824-127.97824c-3.051489 1.454065-6.184898 2.744293-9.379746 3.870681l0 266.97461c37.273227 13.188988 63.99936 48.721433 63.99936 90.520695 0 53.02219-42.98709 96.00928-96.00928 96.00928s-96.00928-42.98709-96.00928-96.00928c0-41.799262 26.726133-77.331707 63.99936-90.520695l0-266.97461c-37.273227-13.188988-63.99936-48.721433-63.99936-90.520695 0-14.827372 3.358686-28.856031 9.359266-41.389666l-78.171378-78.171378-295.892081 295.871601c-25.743103 25.784062-25.743103 67.542365 0 93.285467l447.114889 447.073929c25.743103 25.743103 67.480925 25.743103 93.264987 0l445.00547-445.00547c25.763582-25.763582 25.763582-67.542365 0-93.285467z" fill="#a2d8f4" p-id="5068"></path></svg>',
|
||||
},
|
||||
link: "https://git.liteyuki.icu/bot/app",
|
||||
},
|
||||
{
|
||||
icon: {
|
||||
svg: '<svg t="1736700504329" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14158" width="200" height="200"><path d="M944.355556 142.222222c-17.066667-22.755556-45.511111-34.133333-79.644445-34.133333-28.444444 0-68.266667 5.688889-108.088889 22.755555h-5.688889c17.066667 11.377778 34.133333 28.444444 51.2 39.822223 56.888889-17.066667 91.022222-11.377778 96.711111 0 11.377778 11.377778 5.688889 45.511111-22.755555 91.022222 11.377778 17.066667 17.066667 34.133333 28.444444 51.2 0 0 0 5.688889 5.688889 5.688889 22.755556-34.133333 34.133333-62.577778 45.511111-91.022222 11.377778-28.444444 5.688889-62.577778-11.377777-85.333334z" p-id="14159" fill="#a2d8f4"></path><path d="M267.377778 512a45.511111 45.511111 0 1 0 91.022222 0 45.511111 45.511111 0 1 0-91.022222 0Z" p-id="14160" fill="#a2d8f4"></path><path d="M625.777778 614.4c-113.777778 85.333333-227.555556 153.6-324.266667 193.422222-11.377778 5.688889-17.066667 5.688889-28.444444 11.377778 22.755556 17.066667 51.2 34.133333 79.644444 45.511111 51.2 22.755556 108.088889 34.133333 164.977778 34.133333s113.777778-11.377778 164.977778-34.133333c51.2-22.755556 96.711111-51.2 136.533333-91.022222 39.822222-39.822222 68.266667-85.333333 91.022222-130.844445 22.755556-51.2 34.133333-108.088889 34.133334-159.288888 0-51.2-11.377778-102.4-28.444445-153.6-5.688889 5.688889-11.377778 17.066667-17.066667 22.755555-68.266667 79.644444-164.977778 176.355556-273.066666 261.688889zM813.511111 187.733333c-5.688889-5.688889-11.377778-5.688889-11.377778-11.377777-17.066667-17.066667-34.133333-28.444444-51.2-39.822223-22.755556-11.377778-45.511111-28.444444-68.266666-34.133333-56.888889-28.444444-108.088889-39.822222-164.977778-39.822222s-113.777778 11.377778-164.977778 34.133333c-51.2 22.755556-96.711111 51.2-136.533333 91.022222-39.822222 34.133333-68.266667 79.644444-91.022222 130.844445-22.755556 51.2-34.133333 108.088889-34.133334 159.288889 0 51.2 11.377778 96.711111 22.755556 142.222222-22.755556 34.133333-39.822222 68.266667-51.2 96.711111-11.377778 39.822222-5.688889 68.266667 11.377778 91.022222 17.066667 22.755556 45.511111 34.133333 79.644444 34.133334h11.377778c28.444444 0 62.577778-11.377778 96.711111-22.755556-17.066667-11.377778-34.133333-28.444444-51.2-39.822222-51.2 11.377778-85.333333 11.377778-96.711111 0 0-17.066667 5.688889-45.511111 34.133333-96.711111 17.066667 34.133333 39.822222 62.577778 68.266667 91.022222h5.688889c17.066667-5.688889 39.822222-11.377778 62.577777-17.066667 91.022222-34.133333 204.8-102.4 307.2-187.733333 108.088889-85.333333 199.111111-170.666667 256-250.311111l34.133334-51.2c-22.755556-28.444444-39.822222-56.888889-68.266667-79.644445z m-500.622222 420.977778c-56.888889 0-102.4-45.511111-102.4-102.4s45.511111-102.4 102.4-102.4S409.6 455.111111 409.6 512c0 51.2-45.511111 96.711111-96.711111 96.711111z" p-id="14161" fill="#a2d8f4"></path></svg>',
|
||||
},
|
||||
link: "https://lab.liteyuki.icu/@LiteyukiBot",
|
||||
},
|
||||
],
|
||||
search: {
|
||||
provider: "local",
|
||||
options: {
|
||||
locales: {
|
||||
root: {
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "搜索文档",
|
||||
buttonAriaLabel: "打开搜索框",
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "没有找到搜索结果",
|
||||
resetButtonTitle: "清除查询条件",
|
||||
footer: {
|
||||
selectText: "选择",
|
||||
navigateText: "切换",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
en: {
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: "Search",
|
||||
buttonAriaLabel: "Search",
|
||||
},
|
||||
modal: {
|
||||
noResultsText: "No results found",
|
||||
resetButtonTitle: "Reset search query",
|
||||
footer: {
|
||||
selectText: "Select",
|
||||
navigateText: "Navigate",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sitemap: {
|
||||
hostname: "https://bot.liteyuki.icu",
|
||||
},
|
||||
lastUpdated: true,
|
||||
locales: {
|
||||
root: { label: "简体中文", ...zh },
|
||||
en: { label: "English", ...en },
|
||||
},
|
||||
});
|
35
docs/.vitepress/config/en.ts
Executable file
@ -0,0 +1,35 @@
|
||||
import {defineConfig} from 'vitepress'
|
||||
import {ThemeConfig} from "./utils";
|
||||
|
||||
export const en = defineConfig({
|
||||
lang: "en-US",
|
||||
title: "LiteyukiBot",
|
||||
description: "A high-performance, easy-to-use chatbot framework and application",
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{text: 'Deploy', link: '/en/deploy/install'},
|
||||
{text: 'Usage', link: '/en/usage/basic'},
|
||||
{text: 'Extension', link: '/en/store/resource'},
|
||||
{text: 'Develop', link: '/en/dev/guide'},
|
||||
],
|
||||
docFooter: {
|
||||
prev: 'Prev Page',
|
||||
next: 'Next Page'
|
||||
},
|
||||
editLink: ThemeConfig.getEditLink(
|
||||
'Edit this page on GitHub',
|
||||
),
|
||||
footer: {
|
||||
message: 'Page is deployed at <a href="https://meli.liteyuki.icu" target="_blank">Liteyuki Meli</a> and accelerated by <a href="https://cdn.liteyuki.icu" target="_blank">Liteyukiflare</a><br>Documentation built with <a href="https://vitepress.dev/">VitePress</a> | API references generated by <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a>',
|
||||
copyright: ThemeConfig.copyright
|
||||
},
|
||||
outline: ThemeConfig.getOutLine("Page Content"),
|
||||
|
||||
langMenuLabel: 'Language',
|
||||
returnToTopLabel: 'Back to top',
|
||||
sidebarMenuLabel: 'Menu',
|
||||
darkModeSwitchLabel: 'Theme',
|
||||
lightModeSwitchTitle: 'Light Mode',
|
||||
darkModeSwitchTitle: 'Dark Mode',
|
||||
},
|
||||
})
|
6
docs/.vitepress/config/index.ts
Executable file
@ -0,0 +1,6 @@
|
||||
import {defineConfig} from "vitepress";
|
||||
|
||||
import {common} from './common'
|
||||
export default defineConfig({
|
||||
...common,
|
||||
})
|
40
docs/.vitepress/config/utils.ts
Executable file
@ -0,0 +1,40 @@
|
||||
// 本模块储存一些工具函数和引用
|
||||
|
||||
/**
|
||||
* GetEditLink Options
|
||||
* @param text Edit link text
|
||||
*/
|
||||
export const ThemeConfig = {
|
||||
getEditLink: (editPageText: string): { pattern: (params: { filePath: string; }) => string; text: string; } => {
|
||||
return {
|
||||
pattern: ({filePath}: { filePath: string; }): string => {
|
||||
// 匹配 /dev/api或 /{lang}/dev/api
|
||||
const regex = /^[^\/]+\/dev\/api/;
|
||||
console.log(filePath);
|
||||
if (regex.test(filePath)) {
|
||||
// remove {lang}/api prefix
|
||||
filePath = filePath.replace(regex, '')
|
||||
.replace('index.md', '__init__.py')
|
||||
.replace('.md', '.py');
|
||||
// 若文件名(不含扩展)和上级文件夹相同,返回文件夹/__init__.py
|
||||
if (filePath.split('/').pop().split('.')[0] === filePath.split('/').slice(-2, -1)[0]) {
|
||||
filePath = filePath.split('/').slice(0, -1).join('/') + '/__init__.py';
|
||||
}
|
||||
return `https://github.com/LiteyukiStudio/LiteyukiBot/tree/main/liteyuki${filePath}`;
|
||||
} else {
|
||||
return `https://github.com/LiteyukiStudio/LiteyukiBot/tree/main/docs/${filePath}`;
|
||||
}
|
||||
},
|
||||
text: editPageText
|
||||
};
|
||||
},
|
||||
|
||||
getOutLine: (label: string): { label: string; level: [number, number]; } => {
|
||||
return {
|
||||
label: label,
|
||||
level: [2, 6]
|
||||
};
|
||||
},
|
||||
|
||||
copyright: 'Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved'
|
||||
}
|
35
docs/.vitepress/config/zh.ts
Executable file
@ -0,0 +1,35 @@
|
||||
import {defineConfig} from 'vitepress'
|
||||
import {ThemeConfig} from "./utils";
|
||||
|
||||
export const zh = defineConfig({
|
||||
lang: "zh-Hans",
|
||||
title: "轻雪机器人",
|
||||
description: "一个综合性的机器人应用及管理框架",
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{text: '部署', link: '/deploy/install'},
|
||||
{text: '使用', link: '/usage/basic'},
|
||||
{text: '扩展', link: '/store/resource'},
|
||||
{text: '开发', link: '/dev/guide'},
|
||||
],
|
||||
docFooter: {
|
||||
prev: '上一页',
|
||||
next: '下一页'
|
||||
},
|
||||
editLink: ThemeConfig.getEditLink(
|
||||
'在 GitHub 上编辑此页',
|
||||
),
|
||||
footer: {
|
||||
message: '网站部署在 <a href="https://meli.liteyuki.icu" target="_blank">Liteyuki Meli</a> 由 <a href="https://cdn.liteyuki.icu" target="_blank">Liteyukiflare</a> 提供加速服务<br>文档由 <a href="https://vitepress.dev/">VitePress</a> 构建 | API引用由 <a href="https://github.com/LiteyukiStudio/litedoc">litedoc</a> 生成',
|
||||
copyright: ThemeConfig.copyright
|
||||
},
|
||||
outline: ThemeConfig.getOutLine("页面内容"),
|
||||
|
||||
langMenuLabel: '语言',
|
||||
returnToTopLabel: '返回顶部',
|
||||
sidebarMenuLabel: '菜单',
|
||||
darkModeSwitchLabel: '主题',
|
||||
lightModeSwitchTitle: '轻色模式',
|
||||
darkModeSwitchTitle: '深色模式',
|
||||
},
|
||||
})
|
18
docs/.vitepress/theme/index.ts
Executable file
@ -0,0 +1,18 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './liteyuki.scss'
|
||||
|
||||
import StatsBar from '../../components/StatsBar.vue'
|
||||
import PluginStore from '../../components/PluginStore.vue'
|
||||
import ResStore from '../../components/ResStore.vue'
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
app.component('StatsBar', StatsBar);
|
||||
app.component('PluginStore', PluginStore);
|
||||
app.component('ResStore', ResStore);
|
||||
},
|
||||
Layout: StatsBar
|
||||
}
|
149
docs/.vitepress/theme/liteyuki.scss
Executable file
@ -0,0 +1,149 @@
|
||||
:root {
|
||||
--vp-c-brand-1: #149ef8;
|
||||
--vp-c-brand-2: #0434ad;
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #34a3fe 30%, #8d44ff);
|
||||
|
||||
--vp-home-hero-image-background-image: linear-gradient(-45deg, #d0e9ff 50%, #a2d8f4 50%);
|
||||
--vp-home-hero-image-filter: blur(44px);
|
||||
|
||||
--vp-c-gray-1: #eee;
|
||||
--vp-c-gray-2: #aaa;
|
||||
--border-radius-1: 10px;
|
||||
--border-radius-2: 20px;
|
||||
--border-radius-3: 40px;
|
||||
--vp-font-family-base: 'Poppins', 'Punctuation SC', 'Inter', ui-sans-serif, system-ui,
|
||||
'PingFang SC', 'Noto Sans CJK SC', 'Noto Sans SC', 'Heiti SC',
|
||||
'Microsoft YaHei', 'DengXian', sans-serif, 'Apple Color Emoji',
|
||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--vp-font-family-mono: 'Cousine', monospace;
|
||||
|
||||
--red: #ef4444;
|
||||
--liteyuki-color: #149ef8;
|
||||
--button-radius: 6px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-home-hero-image-background-image: linear-gradient(-45deg, #004785 50%, #0374ad 50%);
|
||||
--vp-c-gray-1: #333;
|
||||
--vp-c-gray-2: #666;
|
||||
}
|
||||
|
||||
.tab-buttons {
|
||||
padding: 7px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
height: 60%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.tab-title {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-search-box {
|
||||
border-radius: 100px;
|
||||
width: 80%;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.search-box-div {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.item-search-box {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.item-card {
|
||||
position: relative;
|
||||
border-radius: 15px;
|
||||
background-color: var(--vp-c-gray-1);
|
||||
height: 160px;
|
||||
padding: 16px;
|
||||
margin: 10px;
|
||||
box-sizing: border-box;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
color: var(--vp-c-gray-2);
|
||||
font-size: 13px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
|
||||
/*store*/
|
||||
|
||||
.store-tabs {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.publish-button {
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 10px;
|
||||
background-color: var(--vp-c-brand-1);
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pub-window {
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.pub-option {
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
border: 2px solid var(--vp-c-gray-1);
|
||||
border-radius: var(--button-radius);
|
||||
background-color: var(--vp-c-gray-1);
|
||||
|
||||
&.close {
|
||||
}
|
||||
|
||||
&.submit {
|
||||
background-color: var(--vp-c-brand-1);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import {defineClientConfig} from "vuepress/client";
|
||||
|
||||
import resourceStoreComp from "./components/ResStore.vue";
|
||||
import pluginStoreComp from "./components/PluginStore.vue";
|
||||
import dashComp from "./components/Dash.vue";
|
||||
import homeComp from "./components/Home.vue";
|
||||
import geoComp from "./components/Geo.vue";
|
||||
|
||||
// import ElementPlus from 'element-plus';
|
||||
|
||||
export default defineClientConfig({
|
||||
enhance: ({app, router, siteData}) => {
|
||||
app.component("homeComp", homeComp);
|
||||
app.component("dashComp", dashComp);
|
||||
app.component("resourceStoreComp", resourceStoreComp);
|
||||
app.component("pluginStoreComp", pluginStoreComp);
|
||||
app.component("geoComp", geoComp);
|
||||
// app.use(ElementPlus);
|
||||
},
|
||||
});
|
||||
|
@ -1,62 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, ref} from 'vue'
|
||||
import ItemCard from './PluginItemCard.vue'
|
||||
|
||||
|
||||
let filteredItems = computed(() => {
|
||||
if (!search.value) {
|
||||
return items.value
|
||||
}
|
||||
return items.value.filter(item =>
|
||||
item.name.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.desc.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.author.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.module_name.toLowerCase().includes(search.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
// 插件商店Nonebot
|
||||
let items = ref([])
|
||||
let search = ref('')
|
||||
// 从官方拉取
|
||||
fetch("/assets/plugins.json")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
items.value = data
|
||||
})
|
||||
.catch(error => console.error(error))
|
||||
|
||||
//追加
|
||||
fetch('https://registry.nonebot.dev/plugins.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
items.value = items.value.concat(data)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="market">
|
||||
<h1>插件商店</h1>
|
||||
<p>内容来自<a href="https://nonebot.dev/store/plugins">NoneBot插件商店</a>和轻雪商店,在此仅作引用,具体请访问NoneBot插件商店</p>
|
||||
<!-- 搜索框-->
|
||||
<div class="search-box-div"><input class="item-search-box" type="text" placeholder="搜索插件" v-model="search"/></div>
|
||||
<div class="items">
|
||||
<!-- 使用filteredItems来布局商品 -->
|
||||
<ItemCard v-for="item in filteredItems" :key="item.id" :item="item"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
color: #00a6ff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
@ -1,53 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, ref} from 'vue'
|
||||
import ItemCard from './ResItemCard.vue'
|
||||
import * as url from "node:url";
|
||||
|
||||
// 从public/assets/resources.json加载插件
|
||||
let filteredItems = computed(() => {
|
||||
if (!search.value) {
|
||||
return items.value.reverse()
|
||||
}
|
||||
return items.value.filter(item =>
|
||||
item.name.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.description.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.author.toLowerCase().includes(search.value.toLowerCase())
|
||||
).reverse()
|
||||
})
|
||||
// 插件商店Nonebot
|
||||
let items = ref([])
|
||||
let search = ref('')
|
||||
fetch("/assets/resources.json")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
items.value = data
|
||||
})
|
||||
.catch(error => console.error(error))
|
||||
// 列表倒序
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="market">
|
||||
<h1>主题/资源商店</h1>
|
||||
<div class="search-box-div"><input class="item-search-box" type="text" placeholder="搜索资源" v-model="search" /></div>
|
||||
<div class="items">
|
||||
<!-- 使用filteredItems来布局商品 -->
|
||||
<ItemCard v-for="item in filteredItems" :key="item.id" :item="item"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
color: #00a6ff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
@ -1,47 +0,0 @@
|
||||
import {defineUserConfig} from "vuepress";
|
||||
import theme from "./theme.js";
|
||||
import viteBundler from "@vuepress/bundler-vite";
|
||||
|
||||
export default defineUserConfig({
|
||||
base: "/",
|
||||
|
||||
locales: {
|
||||
"/": {
|
||||
// 设置正在使用的语言
|
||||
lang: "zh-CN",
|
||||
title: "LiteyukiBot 轻雪机器人",
|
||||
description: "LiteyukiBot | 轻雪机器人 | An OneBot Standard ChatBot | 一个OneBot标准的聊天机器人",
|
||||
head: [
|
||||
["script", {"src": "/js/zh/get_data.js", "type": "module"}],
|
||||
]
|
||||
},
|
||||
"/en/": {
|
||||
// 设置正在使用的语言
|
||||
lang: "en-US",
|
||||
title: "LiteyukiBot",
|
||||
description: "LiteyukiBot | An OneBot Standard ChatBot ",
|
||||
head: [
|
||||
["script", {"src": "/js/en/get_data.js", "type": "module"}],
|
||||
]
|
||||
},
|
||||
},
|
||||
head: [
|
||||
// 设置 favor.ico,.vuepress/public 下
|
||||
["script", {src: "/js/style.js", "type": "module"}],
|
||||
['link', {rel: 'icon', href: 'https://cdn.liteyuki.icu/favicon.ico'},],
|
||||
|
||||
['link', {rel: 'stylesheet', href: 'https://cdn.bootcdn.net/ajax/libs/firacode/6.2.0/fira_code.min.css'}],
|
||||
|
||||
[
|
||||
"meta",
|
||||
{
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no",
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
theme,
|
||||
// 和 PWA 一起启用
|
||||
// shouldPrefetch: false,
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
import {navbar} from "vuepress-theme-hope";
|
||||
|
||||
export const enNavbarConfig = navbar([
|
||||
"/en/",
|
||||
{
|
||||
text: "Deploy",
|
||||
link: "/en/deploy/",
|
||||
prefix: "deploy/",
|
||||
},
|
||||
{
|
||||
text: "Usage",
|
||||
link: "/en/usage/",
|
||||
prefix: "usage/",
|
||||
},
|
||||
{
|
||||
text: "Extensions",
|
||||
link: "/en/store/",
|
||||
prefix: "store/",
|
||||
},
|
||||
{
|
||||
text: "Contribute",
|
||||
link: "/en/dev/",
|
||||
prefix: "dev/",
|
||||
},
|
||||
]);
|
@ -1,2 +0,0 @@
|
||||
export * from "./zh.js"
|
||||
export * from "./en.js"
|
@ -1,26 +0,0 @@
|
||||
|
||||
import {navbar} from "vuepress-theme-hope";
|
||||
|
||||
export const zhNavbarConfig = navbar([
|
||||
"/",
|
||||
{
|
||||
text: "安装及部署",
|
||||
link: "/deploy/",
|
||||
prefix: "deploy/",
|
||||
},
|
||||
{
|
||||
text: "使用及功能",
|
||||
link: "/usage/",
|
||||
prefix: "usage/",
|
||||
},
|
||||
{
|
||||
text: "资源及插件",
|
||||
link: "/store/",
|
||||
prefix: "store/",
|
||||
},
|
||||
{
|
||||
text: "开发及贡献",
|
||||
link: "/dev/",
|
||||
prefix: "dev/",
|
||||
},
|
||||
]);
|
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 9.8 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" class="icon" viewBox="0 0 1024 1024"><path fill="#FDD7AD" d="M512 0 335.448 88.272l-70.616 35.312-70.624 35.312-176.552 88.28v529.648L512 1024l494.344-247.176V247.176z"/><path fill="#CBB292" d="m759.176 370.76-70.624 35.304-494.344-247.168 70.624-35.312zM512 494.344V1024L17.656 776.824V247.176z"/><path fill="#7F6E5D" d="M1006.344 247.168v529.656L512 1024V494.344l176.552-88.28v70.624l141.24-70.624v-70.616z"/><path fill="#7F5B53" d="M829.792 335.448v70.624L688.56 476.68v-70.624z"/><path fill="#CBB292" d="m829.792 335.448-70.624 35.312-494.344-247.176 70.624-35.312z"/><path fill="#2C3E50" d="m682.52 550.32 157.032-78.512a17.656 17.656 0 0 1 25.552 15.792v9.32a52.96 52.96 0 0 1-29.28 47.376L678.8 622.8a17.656 17.656 0 0 1-25.552-15.792v-9.312a52.96 52.96 0 0 1 29.28-47.376z"/></svg>
|
Before Width: | Height: | Size: 854 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024"><defs><linearGradient id="a" x1="522.593" x2="522.593" y1="-70.302" y2="-335.937" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#fe5d5a" stop-opacity=".1"/><stop offset=".908" stop-color="#ef1220" stop-opacity=".5"/></linearGradient><linearGradient id="b" x1="107.12" x2="935.038" y1="-373.67" y2="-373.67" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#ff5e59"/><stop offset="1" stop-color="#f01422"/></linearGradient><linearGradient id="c" x1="519.405" x2="519.405" y1="-195.547" y2="-726.816" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#ffe2e2"/><stop offset=".888" stop-color="#ff8e8e"/></linearGradient><linearGradient id="d" x1="191.5" x2="483.9" y1="-564.9" y2="-564.9" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#e92700" stop-opacity=".3"/><stop offset=".013" stop-color="#ef1220" stop-opacity=".2"/></linearGradient><linearGradient id="e" x1="403.502" x2="253.121" y1="-847.32" y2="-586.853" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#ff5e59"/><stop offset=".201" stop-color="#f01422"/></linearGradient><linearGradient id="f" x1="330.485" x2="330.485" y1="-801.787" y2="-625.789" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#ff5e59"/><stop offset=".201" stop-color="#f01422"/></linearGradient><linearGradient id="g" x1="397.351" x2="256.845" y1="-647.231" y2="-890.596" gradientUnits="userSpaceOnUse" spreadMethod="pad"><stop offset="0" stop-color="#ffa6a6"/><stop offset=".908" stop-color="#ff6b5d"/></linearGradient></defs><path fill="url(#a)" d="M501.2 662.3 327.6 763.8c-13.9 8.1-14.2 28.1-.5 36.7l179.1 97.7c10.9 5.9 24.1 5.9 34.9-.1l177-97.9c13.6-8.5 13.4-28.3-.3-36.5l-168.4-101c-14.8-9-33.3-9.1-48.2-.4Z"/><path fill="#f63037" d="m110.2 525.7-3.1 77.6 57.5 18.5L184 519.4Z"/><path fill="url(#b)" d="m476.6 363.5-328 154.6c-21 42.7-55.4 65.4-35.5 103.5 4.2 8 9.4 14.4 15.4 18.1l358.2 195.5c21.8 11.9 48.1 11.8 69.8-.2l354-195.8c27.2-16.9 34.8-90.3 7.3-106.8L573 364.1c-29.7-17.8-66.6-18-96.4-.6Z"/><path fill="url(#c)" d="M476.6 298.7 129.4 501.6c-27.8 16.3-28.4 56.3-1 73.3l358.2 195.5c21.8 11.9 48.1 11.8 69.8-.2l354-195.8c27.2-16.9 26.9-56.6-.6-73.1L573 299.3c-29.7-17.8-66.6-18-96.4-.6Z"/><path fill="#ff8989" fill-opacity=".31" d="m481.2 387.8 39.4 123.4c1.1 3.4 4 6 7.6 6.6l173.4 30.4-33-118.3c-.9-3.3-3.6-5.8-7-6.5l-180.4-35.6ZM327 499.2l40.4 101.1L496.7 525c2.5-1.5 3.7-4.5 2.7-7.3l-36-106.8-127.6 65c-8.6 4.3-12.4 14.4-8.8 23.3ZM523.8 540.5l-140.3 77.2L567.2 659c3.2.7 6.6.1 9.3-1.6l134.6-85-174.7-33.8c-4.3-1-8.7-.3-12.6 1.9Z"/><path fill="url(#d)" d="M483.9 406.1c0 35.46-65.46 64.2-146.2 64.2s-146.2-28.74-146.2-64.2c0-35.46 65.46-64.2 146.2-64.2s146.2 28.74 146.2 64.2Z"/><path fill="url(#e)" d="m254.2 188.4-123 83.1c-1.8 1.3-2.6 3.6-1.8 5.7l39.1 110.6c.6 1.7 2 2.9 3.8 3.2l221.8 40.5c1.3.3 2.7-.1 3.7-.8l131.7-93.6c1.9-1.4 2.6-3.9 1.7-6.1l-49.4-107c-.6-1.5-2.1-2.6-3.7-2.8l-220.3-33.5c-1.3-.2-2.6.1-3.6.7Z"/><path fill="url(#f)" d="m528.6 274.5 3 59.1-205 65.6-177.2-72.7-20-49.2 1.9-54.1Z"/><path fill="url(#g)" d="m250.6 138-112.3 76c-6 4.1-8.5 11.7-6.1 18.5l34.2 96.6c1.9 5.4 6.6 9.3 12.1 10.4l211 38.5c4.3.7 8.6-.2 12.1-2.7l120.5-85.5c6.3-4.4 8.4-12.7 5.3-19.7l-43.1-93.5c-2.2-4.9-6.8-8.3-12.1-9.1L262 135.6c-4-.7-8 .2-11.4 2.4Z"/><path fill="#fff" d="m419.8 252.8-79-11-29-57.7c-3.8-7.6-13.2-10.7-20.8-6.9-7.6 3.8-10.7 13.2-6.9 20.8l26.6 52.9-61.8 42.2c-7.1 4.8-8.9 14.5-4.1 21.5 3 4.4 7.9 6.8 12.8 6.8 3 0 6-.9 8.7-2.7l68-46.4 81.1 11.2c.7.1 1.4.1 2.1.1 7.6 0 14.3-5.6 15.3-13.4 1.4-8.4-4.5-16.2-13-17.4Z"/></svg>
|
Before Width: | Height: | Size: 3.6 KiB |
@ -1 +0,0 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>
|
Before Width: | Height: | Size: 963 B |
@ -1 +0,0 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
Before Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 9.0 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" class="icon" viewBox="0 0 1536 1024"><path fill="#1296db" d="M1425.067.256H110.933A110.933 110.933 0 0 0 0 110.848v723.627a110.933 110.933 0 0 0 110.933 110.933h1314.39c61.269 0 110.933-49.75 110.677-110.677V110.848A110.933 110.933 0 0 0 1425.067.256z" class="selected" data-spm-anchor-id="a313x.7781069.0.i4"/><path fill="#FFF" d="M664.747 723.797V435.883L517.12 620.373l-147.456-184.49v288l-148.053-67.158V221.781h147.626l147.627 184.576 147.541-184.576h147.627v565.76z"/><path d="M1024 0h426.667A85.333 85.333 0 0 1 1536 85.333v768a85.333 85.333 0 0 1-85.333 85.334H1024V0z" opacity=".1"/><path fill="#FFF" d="m1256.96 731.307-170.667-216.491h113.75V304.64h113.749v210.176h113.835z" opacity=".5"/></svg>
|
Before Width: | Height: | Size: 771 B |
@ -1,20 +0,0 @@
|
||||
[
|
||||
{
|
||||
"module_name": "liteyukibot-plugin-nonebot",
|
||||
"project_link": "liteyukibot-plugin-nonebot",
|
||||
"name": "NoneBot插件",
|
||||
"desc": "在轻雪中使用NoneBot,为NoneBot开发者提供了更多便捷功能(已内置)",
|
||||
"author": "snowykami",
|
||||
"homepage": "https://github.com/LiteyukiStudio/liteyukibot-plugin-nonebot",
|
||||
"tags": [
|
||||
{
|
||||
"label": "server",
|
||||
"color": "#aeeaa8"
|
||||
}
|
||||
],
|
||||
"is_official": true,
|
||||
"type": "application",
|
||||
"valid": true,
|
||||
"version": "rolling"
|
||||
}
|
||||
]
|
@ -1,291 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1366 768">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: url(#_未命名的渐变_8);
|
||||
}
|
||||
|
||||
.cls-1, .cls-2, .cls-3, .cls-4, .cls-5, .cls-6, .cls-7, .cls-8, .cls-9, .cls-10, .cls-11, .cls-12, .cls-13, .cls-14, .cls-15, .cls-16, .cls-17, .cls-18, .cls-19, .cls-20, .cls-21, .cls-22, .cls-23, .cls-24, .cls-25, .cls-26, .cls-27, .cls-28, .cls-29, .cls-30, .cls-31, .cls-32, .cls-33, .cls-34 {
|
||||
stroke-width: 0px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: url(#_未命名的渐变_9-3);
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
fill: url(#_未命名的渐变_11);
|
||||
}
|
||||
|
||||
.cls-4 {
|
||||
fill: url(#_未命名的渐变_11-4);
|
||||
}
|
||||
|
||||
.cls-5 {
|
||||
fill: url(#_未命名的渐变_5);
|
||||
}
|
||||
|
||||
.cls-6 {
|
||||
fill: url(#_未命名的渐变_55);
|
||||
}
|
||||
|
||||
.cls-7 {
|
||||
fill: url(#_未命名的渐变_11-5);
|
||||
}
|
||||
|
||||
.cls-8 {
|
||||
fill: url(#_未命名的渐变_65);
|
||||
}
|
||||
|
||||
.cls-9 {
|
||||
fill: url(#_未命名的渐变_3-2);
|
||||
}
|
||||
|
||||
.cls-10 {
|
||||
fill: url(#_未命名的渐变_7-3);
|
||||
}
|
||||
|
||||
.cls-11 {
|
||||
fill: url(#_未命名的渐变_7);
|
||||
}
|
||||
|
||||
.cls-12 {
|
||||
fill: url(#_未命名的渐变_58);
|
||||
}
|
||||
|
||||
.cls-13 {
|
||||
fill: url(#_未命名的渐变_3-3);
|
||||
}
|
||||
|
||||
.cls-14 {
|
||||
fill: url(#_未命名的渐变_67);
|
||||
}
|
||||
|
||||
.cls-15 {
|
||||
fill: url(#_未命名的渐变_11-2);
|
||||
}
|
||||
|
||||
.cls-16 {
|
||||
fill: url(#_未命名的渐变_72);
|
||||
}
|
||||
|
||||
.cls-17 {
|
||||
fill: url(#_未命名的渐变_71);
|
||||
}
|
||||
|
||||
.cls-18, .cls-35 {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.cls-19 {
|
||||
fill: url(#_未命名的渐变_4);
|
||||
}
|
||||
|
||||
.cls-20 {
|
||||
fill: url(#_未命名的渐变_3);
|
||||
}
|
||||
|
||||
.cls-21 {
|
||||
fill: url(#_未命名的渐变_240);
|
||||
}
|
||||
|
||||
.cls-22 {
|
||||
fill: url(#_未命名的渐变_9-2);
|
||||
}
|
||||
|
||||
.cls-23 {
|
||||
fill: url(#_未命名的渐变_6);
|
||||
}
|
||||
|
||||
.cls-24 {
|
||||
fill: url(#_未命名的渐变_9-4);
|
||||
}
|
||||
|
||||
.cls-25 {
|
||||
fill: url(#_未命名的渐变_66);
|
||||
}
|
||||
|
||||
.cls-26 {
|
||||
fill: url(#_未命名的渐变_7-2);
|
||||
}
|
||||
|
||||
.cls-35 {
|
||||
stroke: #fff;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
|
||||
.cls-27 {
|
||||
fill: url(#_未命名的渐变_9);
|
||||
}
|
||||
|
||||
.cls-28 {
|
||||
fill: url(#_未命名的渐变_9-5);
|
||||
}
|
||||
|
||||
.cls-29 {
|
||||
fill: url(#_未命名的渐变_68);
|
||||
}
|
||||
|
||||
.cls-30 {
|
||||
fill: url(#_未命名的渐变_11-3);
|
||||
}
|
||||
|
||||
.cls-31 {
|
||||
fill: url(#_未命名的渐变_69);
|
||||
}
|
||||
|
||||
.cls-32 {
|
||||
fill: #9cf;
|
||||
}
|
||||
|
||||
.cls-33 {
|
||||
fill: url(#_未命名的渐变_58-2);
|
||||
}
|
||||
|
||||
.cls-34 {
|
||||
fill: url(#_未命名的渐变_4-2);
|
||||
}
|
||||
</style>
|
||||
<linearGradient id="_未命名的渐变_11" data-name="未命名的渐变 11" x1="445.89" y1="235.02" x2="528.25" y2="235.02" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#73fff1"/>
|
||||
<stop offset="1" stop-color="#5cefff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_11-2" data-name="未命名的渐变 11" x1="549.98" y1="292.99" x2="584.05" y2="292.99" xlink:href="#_未命名的渐变_11"/>
|
||||
<linearGradient id="_未命名的渐变_11-3" data-name="未命名的渐变 11" x1="553" y1="212" x2="585" y2="212" xlink:href="#_未命名的渐变_11"/>
|
||||
<linearGradient id="_未命名的渐变_11-4" data-name="未命名的渐变 11" x1="609.82" y1="260.3" x2="698.34" y2="260.3" xlink:href="#_未命名的渐变_11"/>
|
||||
<linearGradient id="_未命名的渐变_11-5" data-name="未命名的渐变 11" x1="702.75" y1="282.24" x2="784.94" y2="282.24" xlink:href="#_未命名的渐变_11"/>
|
||||
<linearGradient id="_未命名的渐变_240" data-name="未命名的渐变 240" x1="835" y1="294" x2="960" y2="294" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#eadeff"/>
|
||||
<stop offset=".28" stop-color="#e0efff"/>
|
||||
<stop offset=".43" stop-color="#d9ecff"/>
|
||||
<stop offset=".59" stop-color="#aedbff"/>
|
||||
<stop offset="1" stop-color="#00d7ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_9" data-name="未命名的渐变 9" x1="664.92" y1="424.34" x2="766.76" y2="424.34" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#2ebbff"/>
|
||||
<stop offset="1" stop-color="#006bff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_9-2" data-name="未命名的渐变 9" x1="761.74" y1="467.72" x2="842.05" y2="467.72" xlink:href="#_未命名的渐变_9"/>
|
||||
<linearGradient id="_未命名的渐变_9-3" data-name="未命名的渐变 9" x1="951.96" y1="394" x2="977.04" y2="394" xlink:href="#_未命名的渐变_9"/>
|
||||
<linearGradient id="_未命名的渐变_9-4" data-name="未命名的渐变 9" x1="952.19" y1="456.86" x2="977.56" y2="456.86" xlink:href="#_未命名的渐变_9"/>
|
||||
<linearGradient id="_未命名的渐变_9-5" data-name="未命名的渐变 9" x1="848.96" y1="437.15" x2="934.09" y2="437.15" xlink:href="#_未命名的渐变_9"/>
|
||||
<linearGradient id="_未命名的渐变_4" data-name="未命名的渐变 4" x1="418.01" y1="402.81" x2="470.25" y2="402.81" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6445ff"/>
|
||||
<stop offset="1" stop-color="#5c86ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_4-2" data-name="未命名的渐变 4" x1="445.81" y1="464.45" x2="466.06" y2="464.45" xlink:href="#_未命名的渐变_4"/>
|
||||
<linearGradient id="_未命名的渐变_72" data-name="未命名的渐变 72" x1="634.1" y1="393.61" x2="649.62" y2="390.81" gradientTransform="translate(-320.36 273.4) rotate(-11.09) scale(1.44 .77)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#c4aeff"/>
|
||||
<stop offset=".43" stop-color="#ce9fff"/>
|
||||
<stop offset=".55" stop-color="#af8eff"/>
|
||||
<stop offset=".72" stop-color="#7d74ff"/>
|
||||
<stop offset=".9" stop-color="#6333ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_58" data-name="未命名的渐变 58" x1="620.28" y1="400.01" x2="636.02" y2="397.18" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#b1ccff"/>
|
||||
<stop offset=".34" stop-color="#b8c0ff"/>
|
||||
<stop offset=".94" stop-color="#cba2ff"/>
|
||||
<stop offset="1" stop-color="#ce9fff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_3" data-name="未命名的渐变 3" x1="469.91" y1="455" x2="478" y2="455" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#5c86ff"/>
|
||||
<stop offset="1" stop-color="#64a2ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_3-2" data-name="未命名的渐变 3" x1="470.95" y1="475.89" x2="477.01" y2="475.89" xlink:href="#_未命名的渐变_3"/>
|
||||
<linearGradient id="_未命名的渐变_65" data-name="未命名的渐变 65" x1="485.09" y1="467.16" x2="502.74" y2="469.91" gradientTransform="translate(-109.75 153.43) rotate(-15.93)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".11" stop-color="#64a2ff"/>
|
||||
<stop offset=".28" stop-color="#62a6ff"/>
|
||||
<stop offset="1" stop-color="#5cb5ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_66" data-name="未命名的渐变 66" x1="506.01" y1="471.79" x2="532.2" y2="471.17" gradientTransform="translate(117.47 -103.02) rotate(12.81)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#5cb5ff"/>
|
||||
<stop offset="1" stop-color="#74e0ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_68" data-name="未命名的渐变 68" x1="559.81" y1="469.17" x2="583.24" y2="468.62" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9cd1ff"/>
|
||||
<stop offset="1" stop-color="#bae0ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_71" data-name="未命名的渐变 71" x1="584.93" y1="460.83" x2="609.05" y2="460.83" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a6d3ff"/>
|
||||
<stop offset=".7" stop-color="#b1ccff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_58-2" data-name="未命名的渐变 58" x1="605.79" y1="473.79" x2="643.63" y2="466.98" xlink:href="#_未命名的渐变_58"/>
|
||||
<linearGradient id="_未命名的渐变_3-3" data-name="未命名的渐变 3" x1="479.91" y1="397.6" x2="514.17" y2="397.6" xlink:href="#_未命名的渐变_3"/>
|
||||
<linearGradient id="_未命名的渐变_5" data-name="未命名的渐变 5" x1="525.59" y1="402.28" x2="558.08" y2="402.28" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#64a2ff"/>
|
||||
<stop offset="1" stop-color="#5cc9ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_69" data-name="未命名的渐变 69" x1="583.43" y1="398.41" x2="604.15" y2="398.41" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#84c9ff"/>
|
||||
<stop offset=".42" stop-color="#b1ccff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_67" data-name="未命名的渐变 67" x1="531.83" y1="464.83" x2="558.02" y2="464.22" gradientTransform="translate(-86.67 132.78) rotate(-12.37)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#74e0ff"/>
|
||||
<stop offset=".56" stop-color="#8dd6ff"/>
|
||||
<stop offset="1" stop-color="#9cd1ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_6" data-name="未命名的渐变 6" x1="531" y1="411" x2="539" y2="411" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#64a2ff"/>
|
||||
<stop offset="1" stop-color="#5cbfff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_7" data-name="未命名的渐变 7" x1="553.98" y1="380.5" x2="559" y2="380.5" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#64ccff"/>
|
||||
<stop offset="1" stop-color="#84c9ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_7-2" data-name="未命名的渐变 7" x1="546.98" y1="383.5" x2="552" y2="383.5" xlink:href="#_未命名的渐变_7"/>
|
||||
<linearGradient id="_未命名的渐变_7-3" data-name="未命名的渐变 7" y1="404.39" x2="561.98" y2="404.39" xlink:href="#_未命名的渐变_7"/>
|
||||
<linearGradient id="_未命名的渐变_8" data-name="未命名的渐变 8" x1="578.42" y1="391.26" x2="586.42" y2="391.26" gradientUnits="userSpaceOnUse">
|
||||
<stop offset=".01" stop-color="#84c9ff"/>
|
||||
<stop offset="1" stop-color="#b1ccff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="_未命名的渐变_55" data-name="未命名的渐变 55" x1="623.35" y1="385.26" x2="623.75" y2="385.26" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#b1c9ff"/>
|
||||
<stop offset=".42" stop-color="#b1ccff"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="_图层_3" data-name="图层 3">
|
||||
<path class="cls-32" d="m447,485c11.04,8.56,30.35.82,33,0,14.37-4.43,15.38-15.33,26-15,10.44.33,13.16,10.98,24,10,6.48-.59,7.04-4.53,16-6,8-1.31,8.66,1.66,17,1,12.76-1.01,15.73-8.33,24-6,8.42,4.47,11.58,6.51,22,5,0,0,11.3-1.75,32-10,1.42-9.07,4.72,6.12,11.99,12,10.1,9.09,19.95-.4,31,8,10.86,8.26,13.5,26.66,13,31-1.65,4.39,6.37,10.16,6,10-4.41-.77-20.72-10.82-25-11-6.8-1.26-15.53-2.26-24-5-17.1-5.24-15.17-10.82-34-10-7.53.04-6.69-.47-12,1-2.54-.23-9.74.73-13-1-18.29-11.87-9.94,11.78-36,3-9.47,1.86-14.72.65-18.02-1.12-2.21-1.19-4.61-5.33-6.74-4.61-.57.19-.74.58-2.24,1.74-1.2.93-2.27,1.58-3,2-.91.36-1.91.7-3,1-2.93.8-5.59,1.02-7.75,1.02-.74,0-1.87-.01-3.25-.02-3.97,0-3.61.03-4,0-2.87-.21-3.75-.93-7-1-.42,0-.77,0-1,0h-6c-3,.22-5.39.65-7,1-1.72.37-3.36.82-10,3-3.07,1.01-4.59,1.59-6,2-1.81.53-5.13,1.49-9,2-5.07.67-9,.3-12,0-6.54-.65-11.56-2.18-14-3-4.6-1.55-26.12-13.37-20-10,0,0,0,0,0,0-.03-.02-20.88-13.37-28-32-1.09-2.85-2-6-2-6-.52-1.8-1.44-5.03-2-9-.44-3.12-1.34-9.53,0-10,1.69-.59,6.23,8.51,7.27,10.48,5.15,9.76,18.12,22.54,52.73,35.52Z"/>
|
||||
<path class="cls-32" d="m633,394c-13.63,7.43-2.93,57.29,2,57,1.82-.11,1.13-6.97,8-16,3-3.94,3.81-3.37,5-6,.88-3.8,2.06-11.66-2-19-.61-1.11-1.29-2.11-2-3-.31-.36-.8-1.04-1-2-.06-.32-.19-.91,0-1,.26-.13.82.87,2,2,.84.81,1.71,1.61,3,2,1.06.32,1.94.17,3,0,1.38-.23,2.37-.69,3-1,1.31-.64,2.25-1.09,3-2,1.84-2.22,1.14-5.41,1-6-.33-1.36-.69-1.29-2-4-.87-1.8-.57-1.55-2-5-.49-1.19-1-2.79-2-6-.12-.39-.37-1.22,0-2,0,0,.29-.6,1-1,1.98-1.11,11.6.55,15,1,2.66.35,13.92,1.61,15.83,2.95.42.3.8.64,1.17,1.05,2.43,2.73.93,4.31,3,9,3.83,8.69,13.16,12.57,19,15,5.09,2.12,8.54,2.5,13,3,6.22.69,7.53-.22,8-1,.74-1.23-.27-2.7-1-5-1.53-4.78-.3-8.09,0-12,.51-6.64-1.77-13.74-4-17-9.26-13.54-41.29,4.77-71-2-1.28-.29-9.89-2.3-12,1-1.87,2.94,2.99,7.55,1,12-1.49,3.33-5.5,3.63-8,5Z"/>
|
||||
<path class="cls-32" d="m683,228c-22.42,19.49,74.7,203.11,32,245-9.08,8.91-26.9,13.94-28,28-.65,8.33,4.78,18.3,13,23,13.88,7.94,28.83,2.05,33-1,2.68-1.96,4-4,4-4,1.44-2.22,1.56-3.91,3-8,.76-2.17,1.5-3.9,2-5,.43-1.13.95-2.86,1-5,.04-1.88-.32-2.29-.25-4.13.04-1.01.22-5.22,2.25-5.87.27-.09,1.3-.35,3,1-.17-.41-.33-.87-.21-.95.24-.16,1.16,1.42,2.21,1.95,2.87,1.44,7.56-.07,8-2-10.79-5.85-14.4-6.84-15-6-.79,1.11,3.49,5.56,3,6-.37.33-3.05-1.93-3-2,.05-.07,3.08,1.97,4,3,.08.09.44.51,1,1,.23.2.43.36.55.46.1.12.26.31.45.54,2.9,3.62,4.2,7.01,4.62,8.05.92,2.28,2.67,5.77,6.38,10.95,15.05,16.54,34.83,19.18,54,9,16.33,3.81,7.85,10.54,33,5,25.9-4.5,50.39,1.98,49-25-1.26-10.66-5.86-19.02,0-10,8.68,14.17,21.69,39.51,43,27,6.44-4.99,5.9-9.29,8-16,1.22-1.48,4.53-4.38,6-4,.01.08.16,1-.41,1.5-.6.53-1.8.43-2.59-.5,2.97,10.52,12.31,17.02,21,16,7.93-.94,13.74-10.13,14.27-11.06.54-.96.98-1.97.98-1.97s.41-.95.75-1.97c1.19-3.64,1.46-7.4,1.46-7.4.88-11.86.98-15.27.98-15.27.35-11.02.5-9.78.67-17.66.19-8.34-.04-7.03.13-13.62,0,0,.55-21.79-3.25-26.05-.48-.54-1-1-1-1-1.02-.91-1.79-1.28-3-2,0,0-1-.67-3-2-1-.67-2.08-1.22-3-2-1.25-1.06-1.85-1.94-3-2-.39-.02-.52.07-1,0-1.2-.18-1.99-1.02-2-1-.02.03.5.41,3,2,.1-.62,1.27-2.67,2-3,5.54-4.98,5.58-5.38,8-10,6.12-15.03-2.92-19.21-14-26-1.23-1.16-1.87-.9-3-1-.59-2.25-2.17-3.18-3-6-1.01-2.71-2.29-10.67-2-12,.57-5.41,2.39-8.84,4-11,2.1-2.82,3.85-3.49,6-7,1.22-2,2.84-4.65,3-8,.25-5.38-3.39-9.63-8-15-2.47-2.87-5.06-5.17-6-6-2.42-2.13-4.22-3.42-5-4-5.14-3.8-8.31-10.94-9.7-14.15-5.32-12.26-7.9-23.86-8.3-32.85-1.17-26.5-38.54-51.77-63-35-7.04,5.65-2.81,10.14-11,18-10.42,10-22.57,7.8-34,13-5.71,3.43-10.18.22-16-2-9.95-3.09-18.5-13.48-24-22-1.52-1.57-3.98-3.73-7.79-5.64-30.14-4.8-47.97-7.45-51.21-7.36-.78.02-4.27.18-7.57-1.74-7.85-9.54-30.21,6.06-40.43,13.74Z"/>
|
||||
<path class="cls-32" d="m667,174c-4.66.36-8.11,1.64-10.79,3.57-13.35,9.62-7.67,24.47-21.35,37.56-3.88,3.71-4.86,2.87-33.86,12.87-.06.02-2.46.85-4,0-.23-.13-.75-.41-1-1-.23-.54-.15-1.16-.12-1.33.02-.16.09-.51.12-.67h0c1.24-1.71,8.11-11.55,4.97-21.02-3.76-11.34-20.93-19.28-39.97-12.98-12.11,2.27-15.97.27-17.33-1.85-1.94-3.02.84-6.86,5.33-19.16,3.86-10.58,5.89-16.13,6-22,.1-5.49-1.43-13.73-10-24-23.21-14.8-47-13.43-56-2-1.46,1.85-5.64,7.92-4,20-3.3,4.02-9.31,1.14-20,4-10.63,1.96-20.69,9.46-13,23,5.63,9.91,94.53,145.36,192.09,115.49,50.17-15.36,72.52-65.2,72.91-66.49.03-.1.51-1.68,0-2-.15-.1-.3-.03-1,0h-3c-1.55,0-3.44-.77-4-1-.5-.2-1.8-.75-5-3-1.04-.73-2.42-1.73-4-3-3.1-.72-4.4-1.96-5-3-.3-.52-.38-.9-1-2-1.21-2.14-1.61-1.92-2-3-.34-.93-.04-1.09,0-5,0-.35,0-.06,0-2,0-3.6.02-3.67,0-4-.12-1.85-.9-3.16-2-5-2.63-4.41-6.25-6.57-7-7-1.67-.96-2.99-1.38-5-2-2.56-.79-6.28-1.69-11-2Z"/>
|
||||
</g>
|
||||
<g id="_背景" data-name="背景">
|
||||
<path class="cls-18" d="m572,182c-16.42-3.08-26.21,8.1-31,4-7.63-6.54,18.33-33.97,9-55-6.88-15.51-30.12-21.13-45-21-3.33.03-16.49.44-31,9-30.76,18.15-37.62,55.27-56,109-20.03,58.55-43.71,77.3-45,119-.4,13.04.88,31.37,1,33,2.91,40.64,9.7,47.97,12,64,.27,1.85.98,7.34,5,12,.83.96,1.59,1.64,2.01,2,.47.48,1.15,1.18,1.99,2,10.84,10.63,27.33,20.18,27.33,20.18,17.89,10.12,26.84,15.18,35.66,13.82,3.19-.49,6.88-1.68,16.62-3.27,3.46-.56,6.46-.79,12.39-1.73,3.95-.63,7.36-.89,10-1,3.64-.15,6.36-.03,7,0,4.66.22,8.01.84,9,1,3.81.61,10.14.32,21-4,3.96.13,4.67,2.49,9,4,4.59,1.6,5.73-.37,15,0,16.7,2.72,12.4-.95,25-4,5.48-.56,5.78,1.97,14,3,9.86,2.45,36.35-8.51,48,1,6.44,5.27,9.1,4.24,16,6,7.05,3.78,15.85,4.35,23,8,18.2,11.17,34.14,20.96,51,2,5.59-6.98,3.83-12.43,8-14,7.13-2.81,31.59,30.21,58,23,15.36-6.57,13.31-4.51,28,1,5.68,1.04,23.32-3.84,33-4,12.6-.87,15.51.92,21-2,11.5-6.32,8.35-12.82,9-21,6.52,3,17.82,31.94,43,18,6.28-4.14,7.41-10.27,11-10,3.81.29,3.43,7.28,9,11,7.22,4.82,20.84,1.79,26-6,1.88-2.84,1.95-5.28,2-16,.06-12.86,2.5-34.29,1-57-.27-4.14-.62-6.12-2-8-1.81-2.47-4.68-3.81-7.73-8.57-.11-.18-.21-.33-.27-.43,0-.08-.02-.19-.02-.33.03-1.6,1.77-2.75,2.36-3.17,1.19-.85,2.8-2.4,4.66-5.5,10.77-33.99-34.41-21.61-20-59,3.12-6.89,6.55-6.37,8-12,2.32-9.04-4.5-18.26-8-23-5.99-8.1-8.37-6.45-17-17-2.93-3.58-6.84-8.36-9.5-15.5-2.32-6.24-2.48-11.05-2.5-12.5,0-.42,0-.77,0-1,.13-4.73-.28-14.34-6-24-8.66-14.64-25.27-22.26-40-22-22.75.41-39.01,19.59-41,22-4.52,5.48-5.53,9.19-11,12-8.17,4.19-19.82,3.24-29-1-1.04-.48-1.78-.88-2-1-13.03-7.1-12.62-18.04-23-25-.78-.52-2.86-1.85-9.5-3.93-18.42-5.77-40.67-7.51-55.5-8.07-1.93.07-4.76-.05-8-1-3.67-1.08-6.36-2.77-8-4-5.34-3.78-6.82-2.84-9-5-3.59-3.56.14-10.39-3-17-2.84-5.97-10.15-7.96-14-9-2.47-.67-11.2-2.68-20,2-1.88,1-6.08,3.3-9,8-2.37,3.82-1.56,5.46-4,14-2.08,7.28-3.18,10.97-6,13-1.17.85-5.1,3.27-13,1-3.07-.18-7.45,0-12,2-8.86,3.88-12,11.82-14,11-2.79-1.15,5.52-15.64,0-28-5.58-12.5-22.22-15.85-23-16Z"/>
|
||||
<g id="_主体" data-name="主体">
|
||||
<path id="lite-l" class="cls-3" d="m516,141c.03-1.1-.07-2.97-1-5-.89-1.93-2.11-3.1-2.75-3.7-.4-.38-1.57-1.42-3.37-2.29-1.11-.53-2.12-.83-2.88-1.01-.48,0-1.16,0-1.98.04-1.4.09-4.59.32-7.8,1.81-3.86,1.79-6.04,4.59-7.21,6.15-1.03,1.36-.93,1.77-4,8-1.08,2.19-1.79,3.57-2,4-5.9,11.79-12,35-12,35-7.65,29.08-7.7,25.76-12,44-2.8,11.87-4.71,21.49-6,28-.61,3.07-2.21,11.25-4,22,0,0-1.57,9.87-3,30-.1,1.34-.46,7.05,1,14,.85,4.05,3,8,3,8h0c2.28,2.98,4.52,4.83,5.99,5.89,11.06,8,23.32,4.35,57.01,4.11,3.06-.02,5.53-.01,7,0,1.02-.28,2.51-.84,4-2,.52-.41,1.27-1.06,2-2,.45-.58,1.59-1.91,2-4,.21-1.08.43-2.87,0-5-.36-1.17-.7-2.18-1-3-.3-.83-.53-1.39-1-2-.36-.46-.73-.79-1-1-.24-.23-.76-.76-1-1-1.73-1.73-1.87-1.87-2-2-1.25-1.2-2.82-1.65-4-2-5.84-1.71-23-2-23-2-4.12-.07-10.14-.62-17.53-2.99,1.73-17.19,5.56-49.39,13.31-81.46,4.95-20.51,4.35-18.09,8.22-30.55,5.85-18.81,8.77-28.22,11-34,0,0,3.24-8.41,4.63-15.69.44-2.32.84-4.8.84-4.8.18-1.17.35-2.34.53-3.5Z"/>
|
||||
<path id="lite-i-1" class="cls-15" d="m569,240c4.11.31,6.91,2.96,8,4,6.83,6.48,6.93,17.68,7,26,0,.06,0,.03,0,7,0,14.32,0,21.48,0,22,.04,13.27.66,35.34-4,42-1.29,1.84-3,3-3,3-2.97,2.01-6.17,1.99-8,2-1.45,0-7.74-.12-13-5-6.34-5.87-6.06-13.87-6-15,0-.07,0-9.93,0-10,0-38.04,0-37.85,0-38-.02-1.29-.01-3.53,0-8,.03-9.9.15-12.06,1-15,1.28-4.42,3.15-6.95,4-8,1.1-1.36,2.19-2.34,3-3,.7-.58,1.7-1.32,3-2,.98-.52,4.28-2.28,8-2Z"/>
|
||||
<path id="lite-i-1-1" class="cls-30" d="m566.78,196.07c8.85-.96,18.71,7.52,18.2,17.09-.5,9.28-10.62,16.63-19.33,14.46-6.93-1.73-13.7-9.65-12.51-18.4,1.06-7.79,7.93-12.52,13.65-13.14Z"/>
|
||||
<path id="lite-t" class="cls-4" d="m643,219c-5.46,4.9-13.26-2.45-24,3-1.76.89-7.94,4.02-9,10-.72,4.08.94,7.61,1.38,8.43.48.92,2.17,4.11,5.62,5.57,1.09.46,1.2.26,6,1,5.06.78,4.17.82,6,1,2.02.19,4,.68,6,1,.54.09,1.55.25,2,1,.42.71.13,1.6,0,2-.61,1.93-.44,4.05-1,6-1.01,3.51-.87,8.39-1,13-.29,10.62-1.82,12.94-2,20-.11,4.19-.42,18.97,9,31,1.49,1.9,10.06,12.84,21,12,1.28-.1,5.89-.45,9-4,4.48-5.11,2.13-12.61,2-13-1.5-4.54-4.19-4.73-8-10-4-5.53-5.15-11-6-15-1.67-7.89-.83-14.05,0-20,1.22-8.76,3.02-10.14,4-16,.13-.81.46-2.94,2-5,0,0,.85-1.13,2-2,2.17-1.64,8.68-.49,12.72-.42,3.25.06,5.06.09,7.28-.58,1.17-.35,8.31-2.66,10-9,1.37-5.14-1.51-11.55-6-14-3.8-2.07-12.48-2.26-15-3-1.03-.3-1.9-.93-2-1-.47-.34-.82-.6-1-1-.56-1.23.89-2.87,1-3,.54-.96,1.27-2.32,2-4,1.51-3.46,2.99-6.85,3-11,0-1.91.01-6.19-3-10-3.3-4.17-8.02-4.99-9.42-5.24-.92-.16-6.37-1-11.58,2.24-1.61,1-4.15,3-7,9-5.75,12.08-1.75,17.18-6,21Z"/>
|
||||
<path id="lite-e" class="cls-7" d="m735,276c-.58.39-5.22,3.65-5,8,.19,3.92,4.21,6.49,5,7,5.42,3.48,9.31.51,25-1,10.15-.98,16.08-.47,21-5,1.89-1.74,2.72-3.39,3-4,2.32-5.01-.29-10.09-1-14-1.83-10.01-12.11-17.03-15-19-1.39-.95-8.43-5.63-19-7-4.47-.58-13.46-1.75-23,3-8.94,4.45-13.31,11.6-16,16-5.84,9.56-6.79,18.48-7,21-.4,4.87-1.09,14.86,5,25,4.96,8.26,11.87,12.39,15,14,8.24,4.25,15.6,4.12,23,4,9.99-.17,16.58-2.61,23-5,2-.74,5.17-2.02,8-5,1.68-1.77,4.08-4.29,4-8-.07-3.36-2.16-6.53-5-8-2.95-1.53-5.9-.81-9,0-6.07,1.58-6.81,4.01-12,6-6.49,2.49-12.52,1.46-15,1-3.77-.69-9.81-1.81-14-7-3.24-4.01-3.72-8.41-4-11-.26-2.43-1.1-10.07,4-17,.43-.59,7.21-9.48,18-9,1.43.06,9.65.59,14,7,1.16,1.71,2.94,4.33,2,6-2.22,3.93-15.76-4.29-25,2Z"/>
|
||||
<path id="logo-snow" class="cls-21" d="m875,272l13.33,22,9.67-15-8-20,4-6,6,2,9,13,7-11,9,1,3,7-11,13,17,2,4,8-5,4-22-4-13.5,16.8,27.5,5.2,11-14,7,1,3,7-9,11,19,3,4,7-4,5-18-3,7,14-4,4-8-1-10-20-40-8-2-2-20-37-23-4-3-7,4-5,16,3-9-15,4-6,7,1,9,16,9-10,7,2,3,6-10,14Z"/>
|
||||
<path id="yuki-y" class="cls-27" d="m717,426c-18.61-18.39-62.05-50.01-50-71,2.85-4.5,7.34-9.45,17-7,15.19,5.99,14.64,39.18,45,55,8.67-18.92,10.28-33.18,10-43-.12-4.37-.74-12.15,4-16,.82-.55,5.22-3.4,10.85-2.15,3.86.85,6.25,3.17,7.15,4.15.5.6,1.28,1.58,2.09,2.87,8.99,14.33.03,32.06-11.49,69.45-4.1,13.3-6.65,21.58-9.6,33.68-5.81,23.86-8.17,40.38-20,51-11.03,9.91-22.32.03-23-9-2.89-15.02,23.13-56.98,18-68Z"/>
|
||||
<path id="yuki-u" class="cls-22" d="m776,433c-.54-.11-5.36-1.02-9,2-2.31,1.92-3.04,4.55-4,8-.74,2.66-.91,4.8-1,6-.59,8.25,0,15,0,15,1.18,13.55,1.77,20.33,3,23,1.04,2.27,4.07,8.71,11,13,6.21,3.85,12.31,3.91,21,4,.81,0,16.83.09,21-4,.22-.21,1.2-1.26,2-1,.93.3.69,2.05,2,4,0,0,.63.93,2,2,3.54,2.75,12.53,3.41,16-1,.62-.79,1.75-2.64,2-5,.07-.68.05-1.22.02-1.76-.13-2.75-.88-4.83-1.02-5.24-1.31-3.73-3.37-15.69-4-23-.58-6.71.42-5.3,0-19-.11-3.63-.12-9.19-3-15-1.36-2.75-2.63-4.09-4-5-2.95-1.96-6.82-2.22-10-1-.8.31-3.48,1.34-5,4-1.36,2.37-1.11,4.83-1,6,.66,6.98.45,14.01,1,21,.72,9.13.57,11.51-1,14-1.8,2.86-4.42,4.2-6,5-7.58,3.86-15,.82-17,0-2.54-1.04-3.49-2.11-4-3-.74-1.29-.88-2.78-1-4-.13-1.35-.05-2.34,0-3v-16c-.19-7.44-.28-11.16-2-14-.52-.85-3.02-4.98-8-6Z"/>
|
||||
<path id="yuki-i-1-1" class="cls-2" d="m964,382c-6.65.3-12.55,6.12-12,13,.53,6.56,6.7,11.28,13,11,6.65-.3,12.55-6.12,12-13-.53-6.56-6.7-11.28-13-11Z"/>
|
||||
<path id="yuki-i-1" class="cls-24" d="m964,413c-.8.03-3.41.23-6,2,0,0-1.73,1.18-3,3-3.44,4.92-2.32,14.54-2,25,.14,4.66,0,9.33,0,14,0,11.92,0,17.88,0,18-.51,8.41-1.54,11.05,0,16,.77,2.5,1.84,5.92,5,8,3.21,2.11,6.76,1.77,8.36,1.62.77-.07,5.65-.54,8.64-3.62,3.4-3.49,2.66-8.56,2-17-.09-1.11-1.18-15.43-1-28,.1-7.33-.76-14.71,0-22,.11-1.03.52-4.77-1-9-.64-1.78-1.55-4.19-4-6-2.89-2.13-6.05-2.04-7-2Z"/>
|
||||
<path id="yuki-k" class="cls-28" d="m918,409c-.26-.11-.66-.27-1.17-.44,0,0-4.46-1.53-9.91-1-4.47.44-18.59,11.34-31.93,31.43-.35-10.53-.23-21.87.56-33.9.37-5.55.85-10.92,1.44-16.1.26-1.2.52-2.94.41-5.03-.09-1.81-.25-4.96-2.27-8.04-.56-.85-2.9-4.42-7.52-5.51-5.61-1.33-10.01,2.08-10.62,2.58-3.44,2.76-4.45,6.67-5,9-3.6,15.32-3,27-3,27,.42,8.15,1.67,32.57,1,50-.22,5.66.05,11.33,0,17-.05,6.02-.13,9.05,1,13,1.45,5.07,4.08,8.75,6,11,1.19,1.11,3.93,3.36,8,4,3.99.63,7.79-.51,9.84-1.85,11.06-7.21,1.65-39.59,4.55-40.56.39-.13,1.19.88,2.61,3.4,8.89,11.22,14.99,15.39,30,29,7.7,10.13,23.45,3.59,22-8-.19-16.59-39.62-33.08-31.91-39.47,1.89-2.38,6-8.21,6.91-9.53,5.47-7.8,10.83-8.44,13-15,1.34-4.04.69-6.57.43-7.38-1.01-3.15-3.39-4.94-4.43-5.62Z"/>
|
||||
<path id="lite-jp-1" class="cls-19" d="m452,384c-1.75-1-2.61-.17-10,1-2.22.35-7.11,1.06-13,3-1.36.45-2.68.93-3,2-.49,1.65,1.56,4.27,4,5,.32.09.56.13.74.16,2.19.34,3.89-.56,5.26-1.16,1.96-.87,3.64-1.24,7-2,0,0,4.44-1,5,0,.02.04.04.07.04.07.07.18-.02.5-.04,2.93,0,.06,0,.71,0,2,0,5.01.09,5.71,0,7-.2,2.74-.3,4.11-1,5-1.25,1.58-3.23,1.52-7,2-5.62.72-4.41,1.27-10,2-7.19.94-9.49.07-11,2-1.32,1.68-1.32,4.57,0,6,1.74,1.88,5.46.88,9,0,7.35-1.82,19.55-4.84,29-6,4.81-.59,12-1.09,13-4,.57-1.65,0-3,0-3-.06-.14-.62-1.43-2-2-1.19-.49-2.36-.18-3,0-6.78,1.91-9.23,2.82-10,2-.45-.48-.17-1.39,0-2,1.77-6.29,1.22-12.36,1-14-.23-1.67-.84-6.18-4-8Z"/>
|
||||
<path id="liteecho-1" class="cls-34" d="m448,440c-1.02.34-1.72,1.18-2,2-.31.93-.06,1.78,0,2,.38,1.39.25,7.26,0,19-.12,5.74-.36,7.73,0,12,.21,2.49.58,5.11,2,8,.87,1.76,1.83,3.72,4,5,2.08,1.23,4.09,1.14,7,1,2.69-.13,6.51-.31,7-2,.37-1.27-1.18-3.23-3-4-2.78-1.18-4.84.97-7,0-2.17-.97-2.69-4.29-3-7-1.07-9.45-.9-24.04-1-30-.02-1.36-.12-5.21-2-6-.58-.25-1.37-.21-2,0Z"/>
|
||||
<path id="yuki-jp-4-1" class="cls-16" d="m636.06,390.95c-2.11.2-3.55,1.9-3.93,2.35-.57.68-.91,1.34-1.11,1.8,1.09,1.05,6.06,5.64,11.22,4.91,2.33-.33,5.1-1.81,5.34-2.63.03-.09.03-.17.03-.17,0-.29-.33-.71-1.89-1.83-1.33-.96-2.23-1.61-3.3-2.18-.69-.37-1.23-.6-1.68-.79-2.41-1.04-3.62-1.55-4.68-1.45Z"/>
|
||||
<path id="yuki-jp-4" class="cls-12" d="m621,375c.37-.49,1.34-1.8,3-2,2.33-.28,3.93,1.89,4,2,.33.46.44.81,1,3,.59,2.3.88,3.45,1,4,.33,1.56.71,3.58,1,6,.65,5.37.61,6.78,1,10,.79,6.47,1.28,10.5,3,15,.07.18,1.23,3.21,1,7-.08,1.29-.29,2.25-1,3-1,1.07-2.67,1.39-4,1-.58-.17-1.69-.65-3-3-1.53-2.75-1.78-5.26-2-7-.3-2.39-.86-5.79-2-10-1-6.33-2-12.67-3-19-.33-1.67-.67-3.33-1-5-.1-.53-.53-2.95,1-5Z"/>
|
||||
<path id="liteecho-i-1-1" class="cls-20" d="m474,451c-1.86-.04-3.59,1.27-4,3-.56,2.38,1.47,5.01,4,5,2.03-.01,4-1.72,4-4,0-2.25-1.92-3.96-4-4Z"/>
|
||||
<path id="liteecho-i-1" class="cls-9" d="m475,464c-.61-.3-1.38-.31-2,0-.14.07-.62.33-1,1-1.18,2.08-1.01,7.51-1,8,.16,5.45,0,9,0,9-.08,1.78-.22,3.7,1,5,.21.22.94,1,2,1,1.08,0,1.81-.8,2-1,1.05-1.14,1.02-2.72,1-4-.03-2.33.04-4.67,0-7-.05-3.31.17-8.95-1-11-.12-.2-.41-.71-1-1Z"/>
|
||||
<path id="liteecho-t" class="cls-8" d="m492.48,452.64c-.52.03-1.3.07-1.92.55-.25.19-.76.67-1.1,2.68-.15.92-.29,2.26-.14,3.91-1.17.01-3.52.16-5.32,1.22-.38.22-.77.51-1,1-.39.85-.08,1.91.41,2.59.74,1.01,1.99,1.19,3.59,1.41.85.12,1.57.12,2.05.1-.06.76-.12,1.85-.14,3.16-.01,1.22-.03,2.48.14,4.12.15,1.49.3,2.92.96,4.62.39,1.03.78,1.67,1,2,.25.39.74,1.08,1.48,1.76,1.12,1.05,2.67,2.5,4.52,2.24,1.2-.17,2.57-1.06,2.76-2.24.12-.76-.29-1.46-.55-1.92-.43-.76-.87-.99-1.51-1.65-.95-.97-1.44-1.93-1.78-2.61-.71-1.41-.9-2.61-1.1-3.85-.15-.97-.37-2.35-.14-4.12.09-.67.22-1.22.32-1.61.56,0,1.35-.04,2.29-.17,1.54-.21,2.32-.32,2.88-.82.8-.71,1.27-2.03.83-3.01-.13-.3-.38-.61-1-1-1.52-.94-3.22-1.02-4.36-.94.11-.49.27-1.25.41-2.2.49-3.18.14-3.81-.14-4.12-.26-.3-.59-.43-1.24-.69-.4-.16-1.18-.47-2.2-.41Z"/>
|
||||
<path id="liteecho-e" class="cls-25" d="m515.41,469.49c-1.24,0-1.82.11-2.17.53-.63.76-.29,2.24.31,3.15,1.51,2.31,5.53,2.25,7.8,1.77,1.4-.3,4.49-.94,5.98-3.77,1.7-3.21-.04-6.62-.4-7.27-1.86-3.4-5.47-4.29-7.14-4.7-3.37-.83-6.16.05-7.27.4-1.07.34-2.81.91-4.53,2.4-3.45,2.98-3.92,7.09-4,8-.27,3.05.7,5.35,1,6,.27.6,1.17,2.42,3,4,1.04.89,2.16,1.53,3,2,.99.56,1.75.89,2,1,1.02.44,1.88.81,3,1,1.17.2,2.07.1,3,0,.34-.04,1.85-.22,4-1,3.3-1.2,4.59-2.54,5-3,.47-.53.68-.9.71-1.34.06-1.15-1.21-2.31-2.48-2.62-.51-.12-.94-.08-1.23-.05-2.01.26-3.04,1.28-4.31,1.86-2.59,1.19-5.84.41-7.69-.86-1.16-.8-1.95-1.93-2-2-.26-.38-.69-1.07-1-2-.26-.77-.95-2.86,0-5,.82-1.85,2.41-2.69,3-3,2.34-1.23,5.06-1.05,7,0,.69.37,1.64.9,2,2,.29.87.26,2.23-.52,2.84-1,.8-2.36-.34-6.07-.36Z"/>
|
||||
<path id="liteecho-c" class="cls-29" d="m570,456c-1.16,0-4.12.04-7,2-1.54,1.05-2.49,2.26-3,3-1.62,2.38-1.87,4.7-2,6-.12,1.26-.36,4,1,7,2.14,4.72,6.61,6.52,8,7,1.04.36,4.93,1.64,9,0,.94-.38,2.74-1.13,4-3,.45-.66,1.99-2.94,1-5-.54-1.12-1.88-2.25-3-2-1.41.32-1.04,2.48-3,4-1.92,1.48-4.45,1.09-5,1-.54-.08-2.42-.41-4-2-2.4-2.42-2.04-5.66-2-6,.07-.51.43-3.37,3-5,2.25-1.43,5.33-1.38,7,0,.93.77.92,1.55,2,2,1.26.52,3.2.27,4-1,.72-1.15.17-2.56,0-3-.15-.38-.69-1.63-3-3-.98-.58-3.45-2.01-7-2Z"/>
|
||||
<path id="liteecho-h" class="cls-17" d="m590,439c-.92-.49-2.08-.44-3,0-1.8.87-1.99,2.91-2,3v9c0,4,.04,8,0,12-.03,3,.1,6,0,9-.1,3.04-.29,5.38,1,8,.45.91,1.42,2.89,3,3,1.63.11,2.9-1.85,3-2,1.44-2.28.03-4.1,0-9-.02-2.85,0-5.82,2-8,.37-.4,1.8-1.97,4-2,2.44-.04,3.91,1.89,4,2,.92,1.22,1,2.52,1,3-.33,1.67-.67,3.33-1,5-.41,1.12-.91,2.85-1,5-.09,2.3-.16,3.99,1,5,1.28,1.11,3.61,1.02,5,0,1.65-1.21,1.8-3.61,2-7,.08-1.27.04-2.31,0-3v-8c-.02-.84-.16-2.36-1-4-.51-1-1.73-2.93-4-4-3.65-1.72-7.65-.14-8,0-1.5.62-2.24,1.36-3,1-.71-.34-.94-1.4-1-4-.12-5.04.61-6.66,0-10-.56-3.06-1.54-3.76-2-4Z"/>
|
||||
<path id="liteecho-o" class="cls-33" d="m625,458c-4.27-.18-7.17,2.27-8,3-3.05,2.66-3.79,6-4,7-.18.88-1.21,5.84,2,10,2.08,2.69,4.82,3.62,6,4,1.29.42,4.46,1.39,8,0,2.95-1.16,4.51-3.31,5-4,1.43-2.02,1.81-3.97,2-5,.46-2.51.1-4.49,0-5-.67-3.35-2.52-5.47-3-6-.69-.76-3.46-3.8-8-4Z"/>
|
||||
<path id="liteecho-o-white" class="cls-35" d="m623.5,464.5c-2.49.24-3.75,2.55-4,3-.09.17-1.81,3.42,0,6,1.68,2.39,5.6,3.06,8,1,2.1-1.8,2.13-4.93,1-7-.84-1.54-2.7-3.22-5-3Z"/>
|
||||
<path id="lite-jp-2" class="cls-13" d="m481,384c-.71.63-1.32,1.81-1,3,.38,1.44,1.86,1.95,2,2,.77.25,1.44.12,2,0,4.88-1.04,5.31-1.31,6-1,1.18.54,1.54,2.08,2,4,.41,1.72.73,3.08,0,4-.65.81-2.11.89-5,1-1.25.05-2.29.03-3,0-.53.14-1.96.61-3,2-.4.54-1.21,1.61-1,3,.24,1.62,1.7,2.78,3,3,.44.08.79.03,1,0,4.59-.65,6.89-.98,7-1,2.55-.43,3.84-.64,4.45-.34,1.26.62,1.41,1.86,2.55,5.34,0,0,1.48,4.5,4,10,.8,1.75,1.53,3.13,2,4,.16.13,2.42,1.9,5,1,.16-.06,2.44-.88,3-3,.21-.78.1-1.42,0-2-.27-1.54-.96-2.26-2-4-.12-.21.03.04-2-4-.67-1.33-1.32-2.67-2-4-1.91-3.76-2.3-4.3-2-5,.2-.46.49-.53,4-2,1.13-.48,2.45-1.03,4-2,1.13-.71,1.71-1.21,2-2,.06-.17.35-1.03,0-2-.48-1.32-1.88-2.03-3-2-.31,0-.54.07-.66.11-2.2.63-4.77,1.67-5.34,1.89-2.21.88-3.31,1.31-4,1-.42-.19-.77-.54-2-4-1.21-3.42-1.11-3.77-1-4,.42-.85,1.37-.79,6-2,2.46-.64,3.57-1.02,4-2,.3-.68.14-1.39,0-2-.09-.4-.54-2.17-2-3-1.17-.66-2.4-.38-4,0-3.65.88-4.88,2.55-6,2-.55-.27-1.15-1.13-1-4-.42-2-.76-3-1-3h0c-.76-1.48-2.4-2.29-4-2-1.51.27-2.7,1.47-3,3-.17,2.45.41,4.01,1,5,.57.95,1.14,1.36,1,2-.24,1.14-2.45,1.64-4,2-2.38.55-3.11.2-4,1Z"/>
|
||||
<path id="yuki-jp-1" class="cls-5" d="m526,396c-.46,1.12-.62,2.69,0,4,.19.41.79,1.49,2,2,1.22.51,2.43.16,3,0,5-1.43,7.51-2.15,8-2,4.42,1.34,3.64,20.08,7,22,2.14,1.22,4,1,4,1,1.43-.17,3.03-.97,3.02-1,0,0,0,0-.02,0,.27-.2.65-.52,1-1,1.53-2.12.85-5.32-1-10-3.3-8.33-6.24-11.07-5-13,.71-1.1,1.84-.46,5.57-2.36,2.51-1.27,4.06-2.06,4.43-3.64.46-1.98-1.11-4.46-3-5-1.01-.29-2.23.21-4.65,1.22-3.32,1.39-3.58,2.02-4.35,1.78-2.25-.7-.9-6.34-4-8-1.22-.65-2.84-.54-4,0-.31.14-1.56.73-2,2-.24.7-.14,1.29,0,2,.51,2.66,2.08,3.57,2,5.99,0,0,0,0,0,0,.01,0,.02,0,.02,0,.01.1-10.37-.01-12.02,4Z"/>
|
||||
<path id="yuki-jp-2-3" class="cls-31" d="m603,386c-.23-.2-.95-.74-2-1-.58-.14-1.39-.34-2,0-.79.44-.86,1.6-1,3,0,0-.62,6.23-2,9-.43.86-.97,1.66-.97,1.66-.12.18-.24.35-.35.5-.2.27-.42.55-.68.84-1.47,1.68-5.93,4.2-5.93,4.2-3.23,1.82-3.66,2.04-4.07,2.8-.61,1.13-.9,2.9,0,4,.8.97,2.17.99,3,1,.7,0,3.05-.07,7.17-3.17,1.64-1.24,3.78-2.89,5.83-5.83,3.15-4.53,3.72-8.76,4-11,.52-4.2-.4-5.48-1-6Z"/>
|
||||
<path id="liteecho-e2" class="cls-14" d="m540.81,469.18c-1.13.52-1.6.87-1.74,1.41-.25.96.69,2.15,1.62,2.72,2.35,1.44,5.96-.31,7.81-1.71,1.14-.86,3.66-2.76,3.81-5.96.17-3.63-2.85-5.97-3.45-6.41-3.13-2.29-6.78-1.55-8.46-1.22-3.41.68-5.55,2.66-6.41,3.45-.83.76-2.15,2.02-3.08,4.1-1.85,4.16-.53,8.09-.22,8.94,1.05,2.88,2.91,4.54,3.46,5,.5.42,2.09,1.69,4.42,2.34,1.32.37,2.61.46,3.57.53,1.13.08,1.96.06,2.24.05,1.11-.04,2.04-.06,3.14-.37,1.14-.32,1.92-.79,2.71-1.28.29-.18,1.58-.98,3.19-2.61,2.48-2.49,3.07-4.25,3.25-4.84.2-.68.24-1.11.07-1.51-.43-1.07-2.08-1.58-3.36-1.31-.51.11-.88.32-1.13.48-1.71,1.09-2.2,2.45-3.11,3.52-1.84,2.18-5.11,2.86-7.32,2.49-1.39-.23-2.59-.92-2.66-.96-.4-.23-1.08-.67-1.76-1.38-.56-.59-2.08-2.19-2.13-4.52-.04-2.02,1.04-3.46,1.44-3.99,1.59-2.11,4.14-3.1,6.33-2.98.79.04,1.86.12,2.66.96.63.67,1.18,1.91.74,2.79-.57,1.15-2.28.69-5.65,2.26Z"/>
|
||||
</g>
|
||||
<circle class="cls-23" cx="535" cy="411" r="4"/>
|
||||
<ellipse class="cls-11" cx="556.49" cy="380.5" rx="2.51" ry="2.5"/>
|
||||
<ellipse class="cls-26" cx="549.49" cy="383.5" rx="2.51" ry="2.5"/>
|
||||
<circle class="cls-10" cx="557.98" cy="404.39" r="4"/>
|
||||
<circle class="cls-1" cx="582.42" cy="391.26" r="4"/>
|
||||
<circle class="cls-6" cx="590.42" cy="385.26" r="4"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 31 KiB |
@ -1,73 +0,0 @@
|
||||
// 定义全局变量来存储数据
|
||||
|
||||
let globalTotal = 0;
|
||||
|
||||
let globalOnline = 0;
|
||||
|
||||
|
||||
// 从API获取数据并更新全局变量
|
||||
|
||||
function fetchAndUpdateData() {
|
||||
|
||||
Promise.all([
|
||||
|
||||
fetch("https://api.liteyuki.icu/count").then(res => res.json()),
|
||||
|
||||
fetch("https://api.liteyuki.icu/online").then(res => res.json())
|
||||
|
||||
])
|
||||
|
||||
.then(([countRes, onlineRes]) => {
|
||||
|
||||
globalTotal = countRes.register;
|
||||
|
||||
globalOnline = onlineRes.online;
|
||||
|
||||
})
|
||||
|
||||
.catch(err => {
|
||||
|
||||
console.error("Error fetching data:", err);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 更新页面显示,使用全局变量中的数据
|
||||
|
||||
function updatePageDisplay() {
|
||||
|
||||
let countInfo = document.getElementById("count-info");
|
||||
|
||||
if (!countInfo) {
|
||||
|
||||
let info = `<div id="count-info" style="text-align: center; font-size: 20px; font-weight: 500">
|
||||
|
||||
Instances:<span id="total">${globalTotal}</span> Online:<span id="online">${globalOnline}</span></div>`;
|
||||
|
||||
let mainDescription = document.querySelector("#main-description");
|
||||
|
||||
if (mainDescription) {
|
||||
|
||||
mainDescription.insertAdjacentHTML('afterend', info);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 初始调用更新数据
|
||||
|
||||
fetchAndUpdateData();
|
||||
|
||||
updatePageDisplay();
|
||||
|
||||
|
||||
// 设置定时器,分别以不同频率调用更新数据和更新页面的函数
|
||||
|
||||
setInterval(fetchAndUpdateData, 10000); // 每10秒更新一次数据
|
||||
|
||||
setInterval(updatePageDisplay, 1000); // 每1秒更新一次页面显示
|
@ -1,93 +0,0 @@
|
||||
echart = require('echarts');
|
||||
let chart = echarts.init(document.getElementById('main-chart'));
|
||||
const color = ['#9ae5fc', '#dcbf71']; // 自定义图中要用到的颜色
|
||||
console.log("加载图标");
|
||||
// 在地图加载完成后设置所有地区不可选
|
||||
function setAllRegionsUnselectable(geoModel) {
|
||||
const regions = geoModel.get('regions');
|
||||
|
||||
// 遍历所有地区并设置selected为false
|
||||
for (let i = 0; i < regions.length; i++) {
|
||||
const region = regions[i];
|
||||
region.selected = false;
|
||||
}
|
||||
|
||||
// 更新模型以反映更改
|
||||
geoModel.set('regions', regions);
|
||||
|
||||
// 更新图表以显示更改
|
||||
chart.setOption({
|
||||
geo: {
|
||||
regions: regions
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取数据并初始化图表
|
||||
fetch('https://api.liteyuki.icu/distribution')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// 构造 ECharts 需要的数据格式
|
||||
const locations = data.locations;
|
||||
const seriesData = locations.map(location => ({
|
||||
value: [location[1], location[0]] // 直接使用经纬度数组
|
||||
}));
|
||||
console.log(seriesData);
|
||||
// 初始化图表选项
|
||||
chart.setOption({
|
||||
backgroundColor: '#454545',
|
||||
title: {
|
||||
text: 'LiteyukiBot分布demo',
|
||||
subtext: 'LiteyukiBot分布',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 20
|
||||
},
|
||||
top: '10px',
|
||||
left: '10px'
|
||||
},
|
||||
geo: {
|
||||
map: 'world',
|
||||
roam: false,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaColor: '#000',
|
||||
borderType: null, // 设置边界线类型为无
|
||||
borderColor: '#000', // 设置边界线颜色
|
||||
|
||||
},
|
||||
emphasis: {
|
||||
areaColor: '#000',
|
||||
borderType: null, // 设置边界线类型为无
|
||||
borderColor: '#000', // 设置边界线颜色
|
||||
}
|
||||
},
|
||||
regions: [] // 先保留为空
|
||||
},
|
||||
series: [{
|
||||
// 散点效果
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'geo', // 表示使用的坐标系为地理坐标系
|
||||
symbolSize: 5, // 设置散点的大小为20
|
||||
itemStyle: {
|
||||
color: '#ffeb3b', // 黄色
|
||||
},
|
||||
data: seriesData
|
||||
}],
|
||||
textStyle: {
|
||||
fontSize: 1
|
||||
}
|
||||
});
|
||||
|
||||
// 在地图加载完成后设置所有地区不可选
|
||||
chart.on('ready', function () {
|
||||
const geoModel = chart.getModel().componentModels.geo[0];
|
||||
setAllRegionsUnselectable(geoModel);
|
||||
});
|
||||
|
||||
// 自适应窗口大小变化
|
||||
window.addEventListener("resize", function () {
|
||||
chart.resize();
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error fetching data:', error));
|
@ -1,31 +0,0 @@
|
||||
function applyStyle() {
|
||||
// 先检测页面中是否有macos-tab,有则不再添加
|
||||
let tabs = document.body.querySelectorAll('.macos-tab')
|
||||
if (tabs.length > 0) {
|
||||
return
|
||||
}
|
||||
let lineNumbers = document.body.querySelectorAll('[class^="language-"].line-numbers-mode')
|
||||
lineNumbers.forEach((item) => {
|
||||
// 插入现成的html文本
|
||||
let title = item.getAttribute('data-title')
|
||||
let tabStr =
|
||||
"<div class='tab macos-tab' style='display: flex; background-color: #d0e9ff'>" +
|
||||
" <div class='tab-buttons'>" +
|
||||
" <div class='tab-button' style='background-color: #FF5F57'></div>" +
|
||||
" <div class='tab-button' style='background-color: #FFBD2E'></div>" +
|
||||
" <div class='tab-button' style='background-color: #27C93F'></div>" +
|
||||
" </div>" +
|
||||
` <div class='tab-title'>${title}</div>` +
|
||||
" <div style='flex: 1'></div>" +
|
||||
"</div>"
|
||||
// 在代码块前插入选项卡
|
||||
item.insertAdjacentHTML('beforebegin', tabStr);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
applyStyle()
|
||||
// 定时器,每隔1s检查一次
|
||||
setInterval(() => {
|
||||
applyStyle()
|
||||
}, 1000)
|
@ -1,73 +0,0 @@
|
||||
// 定义全局变量来存储数据
|
||||
|
||||
let globalTotal = 0;
|
||||
|
||||
let globalOnline = 0;
|
||||
|
||||
|
||||
// 从API获取数据并更新全局变量
|
||||
|
||||
function fetchAndUpdateData() {
|
||||
|
||||
Promise.all([
|
||||
|
||||
fetch("https://api.liteyuki.icu/count").then(res => res.json()),
|
||||
|
||||
fetch("https://api.liteyuki.icu/online").then(res => res.json())
|
||||
|
||||
])
|
||||
|
||||
.then(([countRes, onlineRes]) => {
|
||||
|
||||
globalTotal = countRes.register;
|
||||
|
||||
globalOnline = onlineRes.online;
|
||||
|
||||
})
|
||||
|
||||
.catch(err => {
|
||||
|
||||
console.error("Error fetching data:", err);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 更新页面显示,使用全局变量中的数据
|
||||
|
||||
function updatePageDisplay() {
|
||||
|
||||
let countInfo = document.getElementById("count-info");
|
||||
|
||||
if (!countInfo) {
|
||||
|
||||
let info = `<div id="count-info" style="text-align: center; font-size: 20px; font-weight: 500">
|
||||
|
||||
全球实例:<span id="total">${globalTotal}</span> 当前在线:<span id="online">${globalOnline}</span></div>`;
|
||||
|
||||
let mainDescription = document.querySelector("#main-description");
|
||||
|
||||
if (mainDescription) {
|
||||
|
||||
mainDescription.insertAdjacentHTML('afterend', info);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 初始调用更新数据
|
||||
|
||||
fetchAndUpdateData();
|
||||
|
||||
updatePageDisplay();
|
||||
|
||||
|
||||
// 设置定时器,分别以不同频率调用更新数据和更新页面的函数
|
||||
|
||||
setInterval(fetchAndUpdateData, 10000); // 每10秒更新一次数据
|
||||
|
||||
setInterval(updatePageDisplay, 1000); // 每1秒更新一次页面显示
|
Before Width: | Height: | Size: 92 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" class="icon" viewBox="0 0 3280.944 2800"><path fill="#41b883" d="M1645.332 601.004h375.675L1081.82 2238.478 142.636 601.004h718.477l220.708 379.704 216.013-379.704z"/><path fill="#41b883" d="M142.636 601.004l939.185 1637.474 939.186-1637.474h-375.675l-563.51 982.484-568.208-982.484z"/><path fill="#35495e" d="M513.188 601.004l568.207 987.23 563.511-987.23h-347.498l-216.013 379.704-220.708-379.704zM1607.792 1311.83l594.678 2.293 187.353-316.325-598.662 2.292zM2198.506 1909.57C2867.436 732.7 2939.502 605.426 2937.874 603.78c-.715-.723 45.303-1.314 102.262-1.314s103.562.428 103.562.951c0 .523-208.57 367.978-463.491 816.567L2216.715 2235.6l-102.1.596-102.102.596z"/><path fill="#41b883" d="M1680.563 2233.328c0-1.34 168.208-298.145 440.375-777.048a4135645.775 4135645.775 0 00337.619-594.19l146.13-257.25 170.746-.04 170.747-.04-5.536 9.741c-3.044 5.358-43.727 77.302-90.407 159.875-85.356 150.992-337.562 595.163-656.602 1156.373l-172 302.559-170.536.588c-93.795.322-170.536.069-170.536-.567z"/><path fill="#35495e" d="M1429.783 1625.351l594.679 2.292 187.353-316.324-598.662 2.292z"/><path fill="#41b883" d="M1524.207 1464.903l608.285 6.877 173.746-320.909h-619.072z"/></svg>
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,10 +0,0 @@
|
||||
import {sidebar} from "vuepress-theme-hope";
|
||||
|
||||
export const enSidebarConfig = sidebar(
|
||||
{
|
||||
"/en/deploy/": "structure",
|
||||
"/en/usage/": "structure",
|
||||
"/en/store/": "structure",
|
||||
"/en/dev/": "structure",
|
||||
}
|
||||
)
|
@ -1,2 +0,0 @@
|
||||
export * from "./zh.js"
|
||||
export * from "./en.js"
|
@ -1,11 +0,0 @@
|
||||
import {sidebar} from "vuepress-theme-hope";
|
||||
|
||||
|
||||
export const zhSidebarConfig = sidebar(
|
||||
{
|
||||
"/deploy/": "structure",
|
||||
"/usage/": "structure",
|
||||
"/store/": "structure",
|
||||
"/dev/": "structure",
|
||||
}
|
||||
)
|
@ -1,7 +0,0 @@
|
||||
// you can change config here
|
||||
$colors: #c0392b, #d35400, #f39c12, #27ae60, #16a085, #2980b9, #8e44ad, #2c3e50,
|
||||
#7f8c8d !default;
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
// place your custom styles here
|
||||
|
||||
:root {
|
||||
--code-window-border-radius: 10px;
|
||||
--button-distance: 8px;
|
||||
}
|
||||
|
||||
#main-title {
|
||||
font-family: ColorTube, "Fira Code", serif;
|
||||
color: #ff0000 !important; /* 你想要的颜色 */
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: ColorTube;
|
||||
src: url("/assets/fonts/ColorTube.woff") format("woff")
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: "Fira Code", monospace !important;
|
||||
}
|
||||
|
||||
.vp-hero-image {
|
||||
overflow: hidden;
|
||||
padding: -50px;
|
||||
}
|
||||
|
||||
#main-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-hope-content pre {
|
||||
overflow: auto;
|
||||
margin: 0 0;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
line-height: 1.375;
|
||||
}
|
||||
|
||||
// 移除该before
|
||||
.theme-hope-content pre::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.theme-hope-content > div[class*=language-] {
|
||||
margin: 0 0 0 0;
|
||||
// 仅下半部分有圆弧
|
||||
border-radius: 0 0 var(--code-window-border-radius) var(--code-window-border-radius);
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
height: 25px;
|
||||
margin-bottom: 0;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-top-left-radius: var(--code-window-border-radius);
|
||||
border-top-right-radius: var(--code-window-border-radius);
|
||||
}
|
||||
|
||||
.tab-buttons {
|
||||
padding: 7px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
height: 60%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
margin-right: var(--button-distance);
|
||||
border-radius: 50%;
|
||||
height: 100%;
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
|
||||
.tab-title {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-search-box {
|
||||
border-radius: 100px;
|
||||
width: 80%;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.search-box-div {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.item-search-box {
|
||||
width: 80%;
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
// you can change colors here
|
||||
$theme-color: #00a6ff;
|
@ -1,203 +0,0 @@
|
||||
import {hopeTheme} from "vuepress-theme-hope";
|
||||
import {enSidebarConfig, zhSidebarConfig} from "./sidebar/index.js";
|
||||
import {enNavbarConfig, zhNavbarConfig} from "./navbar/index.js";
|
||||
|
||||
export default hopeTheme({
|
||||
|
||||
hostname: "https://vuepress-theme-hope-docs-demo.netlify.app",
|
||||
hotReload: true,
|
||||
|
||||
locales: {
|
||||
"/": {
|
||||
navbar: zhNavbarConfig,
|
||||
sidebar: zhSidebarConfig,
|
||||
author: {
|
||||
name: "远野千束",
|
||||
url: "https://sfkm.me",
|
||||
}
|
||||
},
|
||||
"/en/": {
|
||||
navbar: enNavbarConfig,
|
||||
sidebar: enSidebarConfig,
|
||||
author: {
|
||||
name: "SnowyKami",
|
||||
url: "https://sfkm.me",
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
iconAssets: "fontawesome-with-brands",
|
||||
|
||||
logo: "https://cdn.liteyuki.icu/static/img/liteyuki_icon_640.png",
|
||||
|
||||
repo: "https://github.com/LiteyukiStudio/LiteyukiBot",
|
||||
|
||||
docsDir: "docs",
|
||||
|
||||
// 页脚
|
||||
footer: "LiteyukiBot",
|
||||
displayFooter: true,
|
||||
|
||||
// 加密配置
|
||||
encrypt: {
|
||||
config: {
|
||||
"/demo/encrypt.html": ["1234"],
|
||||
},
|
||||
},
|
||||
|
||||
// 多语言配置
|
||||
metaLocales: {
|
||||
editLink: "在 GitHub 上编辑",
|
||||
},
|
||||
|
||||
// 如果想要实时查看任何改变,启用它。注: 这对更新性能有很大负面影响
|
||||
// hotReload: true,
|
||||
|
||||
// 在这里配置主题提供的插件
|
||||
plugins: {
|
||||
search: true,
|
||||
// search: true,
|
||||
comment: {
|
||||
provider: "Giscus",
|
||||
repo: "snowykami/LiteyukiBot",
|
||||
repoId: "R_kgDOHVNKpQ",
|
||||
category: "Announcements",
|
||||
categoryId: "DIC_kwDOHVNKpc4CeWxj",
|
||||
},
|
||||
|
||||
components: {
|
||||
components: ["Badge", "VPCard"],
|
||||
},
|
||||
|
||||
// 此处开启了很多功能用于演示,你应仅保留用到的功能。
|
||||
mdEnhance: {
|
||||
echarts: true,
|
||||
alert: true,
|
||||
align: true,
|
||||
attrs: true,
|
||||
codetabs: true,
|
||||
footnote: true,
|
||||
component: true,
|
||||
demo: true,
|
||||
figure: true,
|
||||
imgLazyload: true,
|
||||
imgSize: true,
|
||||
include: true,
|
||||
mark: true,
|
||||
stylize: [
|
||||
{
|
||||
matcher: "Recommended",
|
||||
replacer: ({tag}) => {
|
||||
if (tag === "em")
|
||||
return {
|
||||
tag: "Badge",
|
||||
attrs: {type: "tip"},
|
||||
content: "Recommended",
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
sub: true,
|
||||
sup: true,
|
||||
tabs: true,
|
||||
vPre: true,
|
||||
|
||||
|
||||
// 在启用之前安装 chart.js
|
||||
// chart: true,
|
||||
|
||||
// insert component easily
|
||||
|
||||
// 在启用之前安装 echarts
|
||||
// echarts: true,
|
||||
|
||||
// 在启用之前安装 flowchart.ts
|
||||
// flowchart: true,
|
||||
|
||||
// gfm requires mathjax-full to provide tex support
|
||||
// gfm: true,
|
||||
|
||||
// 在启用之前安装 katex
|
||||
// katex: true,
|
||||
|
||||
// 在启用之前安装 mathjax-full
|
||||
// mathjax: true,
|
||||
|
||||
// 在启用之前安装 mermaid
|
||||
// mermaid: true,
|
||||
|
||||
// playground: {
|
||||
// presets: ["ts", "vue"],
|
||||
// },
|
||||
|
||||
// 在启用之前安装 reveal.js
|
||||
// revealJs: {
|
||||
// plugins: ["highlight", "math", "search", "notes", "zoom"],
|
||||
// },
|
||||
|
||||
// 在启用之前安装 @vue/repl
|
||||
// vuePlayground: true,
|
||||
|
||||
// install sandpack-vue3 before enabling it
|
||||
// sandpack: true,
|
||||
},
|
||||
|
||||
// 如果你需要 PWA。安装 @vuepress/plugin-pwa 并取消下方注释
|
||||
// pwa: {
|
||||
// favicon: "/favicon.ico",
|
||||
// cacheHTML: true,
|
||||
// cachePic: true,
|
||||
// appendBase: true,
|
||||
// apple: {
|
||||
// icon: "/assets/icon/apple-icon-152.png",
|
||||
// statusBarColor: "black",
|
||||
// },
|
||||
// msTile: {
|
||||
// image: "/assets/icon/ms-icon-144.png",
|
||||
// color: "#ffffff",
|
||||
// },
|
||||
// manifest: {
|
||||
// icons: [
|
||||
// {
|
||||
// src: "/assets/icon/chrome-mask-512.png",
|
||||
// sizes: "512x512",
|
||||
// purpose: "maskable",
|
||||
// type: "image/png",
|
||||
// },
|
||||
// {
|
||||
// src: "/assets/icon/chrome-mask-192.png",
|
||||
// sizes: "192x192",
|
||||
// purpose: "maskable",
|
||||
// type: "image/png",
|
||||
// },
|
||||
// {
|
||||
// src: "/assets/icon/chrome-512.png",
|
||||
// sizes: "512x512",
|
||||
// type: "image/png",
|
||||
// },
|
||||
// {
|
||||
// src: "/assets/icon/chrome-192.png",
|
||||
// sizes: "192x192",
|
||||
// type: "image/png",
|
||||
// },
|
||||
// ],
|
||||
// shortcuts: [
|
||||
// {
|
||||
// name: "Demo",
|
||||
// short_name: "Demo",
|
||||
// url: "/demo/",
|
||||
// icons: [
|
||||
// {
|
||||
// src: "/assets/icon/guide-maskable.png",
|
||||
// sizes: "192x192",
|
||||
// purpose: "maskable",
|
||||
// type: "image/png",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
},
|
||||
});
|
@ -1,82 +0,0 @@
|
||||
---
|
||||
home: true
|
||||
icon: home
|
||||
title: 首页
|
||||
heroImage: https://cdn.liteyuki.icu/static/svg/lylogo-full.svg
|
||||
heroImageDark: https://cdn.liteyuki.icu/static/svg/lylogo-full-dark.svg
|
||||
bgImage:
|
||||
bgImageDark:
|
||||
bgImageStyle:
|
||||
background-attachment: fixed
|
||||
heroText: LiteyukiBot
|
||||
tagline: LiteyukiBot 轻雪机器人,综合性的机器人应用及管理框架
|
||||
|
||||
actions:
|
||||
- text: 快速部署
|
||||
icon: rocket
|
||||
link: ./deploy/install.html
|
||||
type: primary
|
||||
|
||||
- text: 使用手册
|
||||
icon: book
|
||||
link: ./usage/basic_command.html
|
||||
|
||||
highlights:
|
||||
- header: 简洁至上
|
||||
image: /assets/image/layout.svg
|
||||
bgImage: https://theme-hope-assets.vuejs.press/bg/2-light.svg
|
||||
bgImageDark: https://theme-hope-assets.vuejs.press/bg/2-dark.svg
|
||||
bgImageStyle:
|
||||
background-repeat: repeat
|
||||
background-size: initial
|
||||
features:
|
||||
- title: 支持多种框架
|
||||
icon: robot
|
||||
details: 兼容nonebot,melobot等,拥有良好的生态支持
|
||||
link: https://nonebot.dev/
|
||||
|
||||
- title: 便捷管理
|
||||
icon: plug
|
||||
details: 使用包管理器,便捷管理插件及资源包
|
||||
|
||||
- title: 主题支持
|
||||
icon: paint-brush
|
||||
details: 使用资源包对外观进行完全自定义
|
||||
link: https://bot.liteyuki.icu/usage/resource_pack.html
|
||||
|
||||
- title: 国际化
|
||||
icon: globe
|
||||
details: 通过资源包支持多种语言
|
||||
link: https://baike.baidu.com/item/i18n/6771940
|
||||
|
||||
- title: 简易使用
|
||||
icon: cog
|
||||
details: 无需繁琐前期过程,开箱即用
|
||||
link: https://bot.liteyuki.icu/deployment/config.html
|
||||
|
||||
- title: 超高性能
|
||||
icon: tachometer-alt
|
||||
details: 500个插件,2s内启动
|
||||
|
||||
- title: 滚动更新
|
||||
icon: cloud-download
|
||||
details: 让你的机器人保持最新提交
|
||||
|
||||
- title: 开源项目
|
||||
icon: code
|
||||
details: 项目遵循MIT LICENCE开源,欢迎各位的贡献
|
||||
|
||||
- header: 快速部署
|
||||
image: /assets/image/box.svg
|
||||
bgImage: https://theme-hope-assets.vuejs.press/bg/3-light.svg
|
||||
bgImageDark: https://theme-hope-assets.vuejs.press/bg/3-dark.svg
|
||||
highlights:
|
||||
- title: 安装 Git 及 Python3.10+
|
||||
- title: 使用 <code>git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1</code> 以克隆项目至本地。
|
||||
details: 如果无法连接到GitHub,可以使用 <code>git clone https://gitee.com/snowykami/LiteyukiBot --depth=1</code>。
|
||||
- title: 使用 <code>cd LiteyukiBot</code> 切换到项目目录。
|
||||
- title: 使用 <code>pip install -r requirements.txt</code> 安装项目依赖。
|
||||
details: 如果你有多个 Python 环境,请使用 <code>pythonx -m pip install -r requirements.txt</code>。
|
||||
- title: 使用 <code>python main.py</code> 启动项目。
|
||||
copyright: © 2021-2024 SnowyKami All Rights Reserved
|
||||
---
|
26
docs/components/ContributorBar.vue
Executable file
@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import {getTextRef} from "./scripts/i18n";
|
||||
import {repoPath, repoURL} from "./scripts/const";
|
||||
|
||||
const contributorImgSrc = `https://contrib.rocks/image?repo=${repoPath}`
|
||||
const contributorsUrl = `${repoURL}/graphs/contributors`
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="contributor-bar">
|
||||
<h2>{{ getTextRef('thx_contributors') }}</h2>
|
||||
<a :href="contributorsUrl">
|
||||
<div class="contributor-list">
|
||||
<img :src=contributorImgSrc alt="Contributors">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contributor-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
0
docs/.vuepress/components/Dash.vue → docs/components/Dash.vue
Normal file → Executable file
0
docs/.vuepress/components/Geo.vue → docs/components/Geo.vue
Normal file → Executable file
0
docs/.vuepress/components/Home.vue → docs/components/Home.vue
Normal file → Executable file
73
docs/.vuepress/components/PluginItemCard.vue → docs/components/PluginItemCard.vue
Normal file → Executable file
@ -2,16 +2,19 @@
|
||||
<div class="item-card">
|
||||
<div class="item-name">{{ props.item.name }}</div>
|
||||
<div class="item-description">{{ props.item.desc }}</div>
|
||||
<div class="tags">
|
||||
<span class="tag" v-for="tag in props.item.tags" :key="tag" :style=getTagStyle(tag.color)>{{ tag.label }}</span>
|
||||
</div>
|
||||
<div class="item-bar">
|
||||
<!-- 三个可点击svg,一个github,一个下载,一个可点击"https://github.com/{{ username }}.png?size=80"个人头像配上id-->
|
||||
<a :href=props.item.homepage class="btn">
|
||||
<a :href=props.item.homepage class="btn" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 16 16">
|
||||
<path fill="currentColor"
|
||||
d="m7.775 3.275l1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0a.751.751 0 0 1 .018-1.042a.751.751 0 0 1 1.042-.018a1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018a.751.751 0 0 1-.018-1.042m-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018a.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0a.751.751 0 0 1-.018 1.042a.751.751 0 0 1-1.042.018a1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<!-- <button class="copy-btn btn"><div @click="copyToClipboard">安装</div></button> 点击后把安装命令写入剪贴板-->
|
||||
<!-- <button class="copy-btn btn"><div @click="copyToClipboard">安装</div></button> 点击后把安装命令写入剪贴板-->
|
||||
<button class="btn copy-btn" @click="copyToClipboard">复制安装命令</button>
|
||||
|
||||
<div class="btn">
|
||||
@ -45,22 +48,26 @@ const copyToClipboard = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const getTagStyle = (backgroundColor: string) => {
|
||||
// 将颜色值转换为 RGB 格式
|
||||
const rgb = backgroundColor.replace(/^#/, '');
|
||||
const [r, g, b] = rgb.match(/.{2}/g).map(x => parseInt(x, 16));
|
||||
|
||||
// 计算亮度
|
||||
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||
|
||||
// 根据亮度决定文字颜色
|
||||
return {
|
||||
backgroundColor: backgroundColor,
|
||||
color: brightness > 128 ? '#000' : '#fff'
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// 复制到剪贴板的函数
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-card {
|
||||
position: relative;
|
||||
border-radius: 15px;
|
||||
background-color: #00000011;
|
||||
height: 160px;
|
||||
padding: 16px;
|
||||
margin: 10px;
|
||||
box-sizing: border-box;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-right: 15px;
|
||||
}
|
||||
@ -75,43 +82,11 @@ button {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
color: #111;
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: $themeColor;
|
||||
}
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.item-bar {
|
||||
position: absolute;
|
||||
@ -123,4 +98,12 @@ button {
|
||||
justify-content: space-between;
|
||||
color: #00000055;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
margin-right: 5px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
91
docs/components/PluginStore.vue
Executable file
@ -0,0 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, ref} from 'vue'
|
||||
import ItemCard from './PluginItemCard.vue'
|
||||
import ToggleSwitch from "./ToggleSwitch.vue";
|
||||
import {getTextRef} from "./scripts/i18n";
|
||||
import pluginsJson from "../public/plugins.json"
|
||||
|
||||
let showLiteyukiPluginOnly = ref(false)
|
||||
let filteredItems = computed(() => {
|
||||
let filtered = items.value
|
||||
if (search.value) {
|
||||
filtered = filtered.filter(item =>
|
||||
item.name.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.desc.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.author.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.module_name.toLowerCase().includes(search.value.toLowerCase())
|
||||
)
|
||||
}
|
||||
if (showLiteyukiPluginOnly.value) {
|
||||
filtered = filtered.filter(item => item.is_liteyuki_plugin)
|
||||
}
|
||||
return filtered
|
||||
})
|
||||
// 插件商店Nonebot
|
||||
let items = ref([])
|
||||
let search = ref('')
|
||||
// 从轻雪官方拉取,添加轻雪插件属性
|
||||
items.value = pluginsJson
|
||||
items.value.forEach(item => {
|
||||
item.is_liteyuki_plugin = true
|
||||
})
|
||||
|
||||
//追加
|
||||
fetch('https://registry.nonebot.dev/plugins.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// 遍历data的每一项,把is_official设为false
|
||||
data.forEach(item => {
|
||||
item.is_official = false
|
||||
})
|
||||
items.value = items.value.concat(data)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="market">
|
||||
<h1>{{ getTextRef('pluginStore') }}</h1>
|
||||
<p>{{ getTextRef('pluginStoreDesc') }}</p>
|
||||
<!-- 搜索框-->
|
||||
<div class="search-box-div">
|
||||
<input class="item-search-box" type="text" v-model="search" :placeholder="getTextRef('search')"/>
|
||||
<ToggleSwitch v-model:modelValue="showLiteyukiPluginOnly"/>
|
||||
{{ getTextRef('liteyukiOnly') }}
|
||||
</div>
|
||||
|
||||
<!-- 按钮们-->
|
||||
<!-- <div class="tab">-->
|
||||
<!-- <button @click="open"-->
|
||||
<!-- </div>-->
|
||||
<div class="items">
|
||||
<!-- 使用filteredItems来布局商品 -->
|
||||
<ItemCard v-for="item in filteredItems" :key="item.id" :item="item"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
color: #00a6ff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.search-box-div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-box-div input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
40
docs/.vuepress/components/ResItemCard.vue → docs/components/ResItemCard.vue
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
<div class="item-description">{{ props.item.description }}</div>
|
||||
<div class="item-bar">
|
||||
<!-- 三个可点击svg,一个github,一个下载,一个可点击"https://github.com/{{ username }}.png?size=80"个人头像配上id-->
|
||||
<a :href=props.item.link class="">
|
||||
<a :href=props.item.link class="" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 16 16">
|
||||
<path fill="currentColor"
|
||||
d="m7.775 3.275l1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0a.751.751 0 0 1 .018-1.042a.751.751 0 0 1 1.042-.018a1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018a.751.751 0 0 1-.018-1.042m-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018a.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0a.751.751 0 0 1-.018 1.042a.751.751 0 0 1-1.042.018a1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83"/>
|
||||
@ -28,32 +28,8 @@ const props = defineProps({
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-card {
|
||||
position: relative;
|
||||
border-radius: 15px;
|
||||
background-color: #00000011;
|
||||
height: 160px;
|
||||
padding: 16px;
|
||||
margin: 10px;
|
||||
box-sizing: border-box;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.item-card:hover {
|
||||
border: 2px solid $themeColor;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
color: $themeColor;
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
@ -61,21 +37,9 @@ const props = defineProps({
|
||||
color: $themeColor;
|
||||
}
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
|
||||
.item-bar {
|
||||
position: absolute;
|
38
docs/components/ResPubWindow.vue
Executable file
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div v-if="isVisible" class="floating-window">
|
||||
<div class="window-content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {defineProps} from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
isVisible: Boolean,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.floating-window {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.window-content {
|
||||
background: var(--vp-c-gray-1);
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
max-width: 60%;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
105
docs/components/ResStore.vue
Executable file
@ -0,0 +1,105 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, ref} from 'vue'
|
||||
import ItemCard from './ResItemCard.vue'
|
||||
import ResPubWindow from "./ResPubWindow.vue";
|
||||
import {getTextRef, formatLang} from "./scripts/i18n";
|
||||
import {RepoUrl} from "./scripts/statsApi";
|
||||
|
||||
import resourcesJson from "../public/resources.json"
|
||||
import {useData} from "vitepress";
|
||||
// formLan
|
||||
|
||||
// 从public/assets/resources.json加载插件
|
||||
let filteredItems = computed(() => {
|
||||
if (!search.value) {
|
||||
return items.value.reverse()
|
||||
}
|
||||
return items.value.filter(item =>
|
||||
item.name.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.description.toLowerCase().includes(search.value.toLowerCase()) ||
|
||||
item.author.toLowerCase().includes(search.value.toLowerCase())
|
||||
).reverse()
|
||||
})
|
||||
// 插件商店Nonebot
|
||||
let items = ref([])
|
||||
let search = ref('')
|
||||
items.value = resourcesJson
|
||||
// 列表倒序
|
||||
|
||||
const isPublishWindowOpen = ref(false)
|
||||
|
||||
let newRes = ref({
|
||||
name: '',
|
||||
})
|
||||
|
||||
function openPublishWindow() {
|
||||
isPublishWindowOpen.value = true
|
||||
}
|
||||
|
||||
function closePublishWindow() {
|
||||
isPublishWindowOpen.value = false
|
||||
}
|
||||
|
||||
let submitLang = ""
|
||||
if (formatLang(useData().site.value.lang) === "zh") {
|
||||
submitLang = "zh"
|
||||
} else {
|
||||
submitLang = "en"
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
const title = encodeURI(`Resource: ${newRes.value.name}`)
|
||||
const issueURL = `${RepoUrl}/issues/new?assignees=&labels=Resource&template=resource_publish_${submitLang}.yml&title=${title}`
|
||||
console.log(issueURL)
|
||||
window.open(issueURL, '_blank')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="market">
|
||||
<h1>{{ getTextRef('resourceStore') }}</h1>
|
||||
<div class="search-box-div"><input class="item-search-box" type="text" :placeholder="getTextRef('search')"
|
||||
v-model="search"/></div>
|
||||
<div class="store-tabs" style="display: flex">
|
||||
<button class="store-button publish-button" @click="openPublishWindow">{{ getTextRef('publishRes') }}</button>
|
||||
</div>
|
||||
<div class="items">
|
||||
<!-- 使用filteredItems来布局商品 -->
|
||||
<ItemCard v-for="item in filteredItems" :key="item.id" :item="item"/>
|
||||
</div>
|
||||
<ResPubWindow class="pub-window" :is-visible="isPublishWindowOpen">
|
||||
<h2>{{ getTextRef("publishRes") }}</h2>
|
||||
<form @submit.prevent="submitForm">
|
||||
<label for="name">{{ getTextRef("resName") }}</label>
|
||||
<input type="text" id="name" v-model="newRes.name" :placeholder="getTextRef('resNameText')"/>
|
||||
<div class="pub-options" style="display: flex; justify-content: center">
|
||||
<button class="pub-option close" type="button" @click="closePublishWindow">{{
|
||||
getTextRef("closeButtonText")
|
||||
}}
|
||||
</button>
|
||||
<button class="pub-option submit" type="submit" @click="submitForm">{{
|
||||
getTextRef("submitButtonText")
|
||||
}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ResPubWindow>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
color: #00a6ff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
301
docs/components/StatsBar.vue
Executable file
@ -0,0 +1,301 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultTheme from "vitepress/theme";
|
||||
import {ref, onMounted, onUnmounted} from "vue";
|
||||
import {statsApi, GithubStats, RepoUrl, StarMapUrl, uploadVisitRecord} from "./scripts/statsApi";
|
||||
import {getTextRef, updateRefData} from "./scripts/i18n";
|
||||
import {onBeforeRouteUpdate} from 'vue-router';
|
||||
|
||||
const {Layout} = DefaultTheme;
|
||||
|
||||
let githubStats: GithubStats | null = null;
|
||||
|
||||
const dataSections = {
|
||||
total: {
|
||||
name: 'total',
|
||||
color: '#00a6ff',
|
||||
value: ref(-1),
|
||||
link: StarMapUrl
|
||||
},
|
||||
online: {
|
||||
name: 'online',
|
||||
color: '#7eff7e',
|
||||
value: ref(-1),
|
||||
link: StarMapUrl
|
||||
},
|
||||
stars: {
|
||||
name: 'stars',
|
||||
color: '#ffcc00',
|
||||
value: ref(-1),
|
||||
link: `${RepoUrl}/stargazers`
|
||||
},
|
||||
forks: {
|
||||
name: 'forks',
|
||||
color: '#ff6600',
|
||||
value: ref(-1),
|
||||
link: `${RepoUrl}/forks`
|
||||
},
|
||||
issues: {
|
||||
name: 'issues',
|
||||
color: '#ff0000',
|
||||
value: ref(-1),
|
||||
link: `${RepoUrl}/issues`
|
||||
},
|
||||
prs: {
|
||||
name: 'prs',
|
||||
color: '#f15df1',
|
||||
value: ref(-1),
|
||||
link: `${RepoUrl}/pulls`
|
||||
},
|
||||
plugins: {
|
||||
name: 'plugins',
|
||||
color: '#a766ff',
|
||||
value: ref(-1),
|
||||
link: './store/plugin'
|
||||
},
|
||||
resources: {
|
||||
name: 'resources',
|
||||
color: '#5a54fa',
|
||||
value: ref(-1),
|
||||
link: './store/resource'
|
||||
},
|
||||
visitors: {
|
||||
name: 'visitors',
|
||||
color: '#00a6ff',
|
||||
value: ref(-1),
|
||||
link: RepoUrl
|
||||
},
|
||||
}
|
||||
|
||||
async function updateData() {
|
||||
// dataSections.online.value.value = await statsApi.getOnline();
|
||||
// dataSections.total.value.value = await statsApi.getTotal();
|
||||
[
|
||||
dataSections.online.value.value,
|
||||
dataSections.total.value.value,
|
||||
dataSections.plugins.value.value,
|
||||
dataSections.resources.value.value,
|
||||
dataSections.visitors.value.value,
|
||||
githubStats,
|
||||
|
||||
] = await Promise.all([
|
||||
statsApi.getOnline(),
|
||||
statsApi.getTotal(),
|
||||
statsApi.getPluginNum(),
|
||||
statsApi.getResourceNum(),
|
||||
statsApi.getVisitCount(),
|
||||
statsApi.getGithubStats(),
|
||||
]);
|
||||
dataSections.stars.value.value = githubStats?.stars || 0;
|
||||
dataSections.forks.value.value = githubStats?.forks || 0;
|
||||
dataSections.issues.value.value = githubStats?.issues || 0;
|
||||
dataSections.prs.value.value = githubStats?.prs || 0;
|
||||
}
|
||||
|
||||
function formatNumber(num: { value: number }): string {
|
||||
return num.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const intervalId = setInterval(updateData, 10000);
|
||||
updateData();
|
||||
uploadVisitRecord();
|
||||
onUnmounted(() => {
|
||||
clearInterval(intervalId);
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeRouteUpdate(() => {
|
||||
updateRefData();
|
||||
});
|
||||
|
||||
console.log(
|
||||
" _ _ _ _ _ ____ _ \n" +
|
||||
" | | (_) | | | (_) _ \\ | | \n" +
|
||||
" | | _| |_ ___ _ _ _ _| | ___| |_) | ___ | |_ \n" +
|
||||
" | | | | __/ _ \\ | | | | | | |/ / | _ < / _ \\| __|\n" +
|
||||
" | |____| | || __/ |_| | |_| | <| | |_) | (_) | |_ \n" +
|
||||
" |______|_|\\__\\___|\\__, |\\__,_|_|\\_\\_|____/ \\___/ \\__|\n" +
|
||||
" __/ | \n" +
|
||||
" |___/ "
|
||||
)
|
||||
|
||||
console.log(
|
||||
getTextRef('easterEgg')
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<template #home-features-before>
|
||||
<div class="stats-bar-content">
|
||||
<div class="stats-bar">
|
||||
<div class="stats-info">
|
||||
<div class="stats-title">{{ getTextRef('stats') }}</div>
|
||||
<div class="sections">
|
||||
<div v-for="section in Object.values(dataSections)" :key="section.name" class="section">
|
||||
<a :href="section.link" target="_blank">
|
||||
<div class="section-tab">
|
||||
<span class="dot" :style="{backgroundColor: section.color}"></span>
|
||||
<span class="text">{{ getTextRef(section.name) }}</span>
|
||||
</div>
|
||||
<div class="number">{{ formatNumber(section.value) }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="starmap">
|
||||
<iframe src="https://starmap.liteyuki.icu/" width="100%" height="300px" class="gamma">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.stats-bar-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.gamma {
|
||||
filter: brightness(1.8);
|
||||
}
|
||||
|
||||
.dark .gamma {
|
||||
filter: brightness(1.0);
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
width: 80%;
|
||||
max-width: 1150px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 10px;
|
||||
border-radius: var(--border-radius-2);
|
||||
background-color: var(--vp-c-gray-1);
|
||||
flex-direction: column; /* 默认纵向布局 */
|
||||
}
|
||||
|
||||
.stats-info{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sections {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 15px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative; /* 使伪元素相对于父元素定位 */
|
||||
border-radius: var(--border-radius-2);
|
||||
}
|
||||
|
||||
.section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border: 0 solid transparent; /* 初始边框为透明 */
|
||||
transition: border 0.1s ease-in-out; /* 添加过渡效果 */
|
||||
border-radius: var(--border-radius-2);
|
||||
pointer-events: none; /* 确保伪元素不会阻挡点击事件 */
|
||||
}
|
||||
|
||||
.section:hover::before {
|
||||
border: 1px solid #00a6ff; /* 悬停时添加边框 */
|
||||
border-radius: var(--border-radius-2);
|
||||
}
|
||||
|
||||
.section-tab {
|
||||
margin-left: 15px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center; /* 确保垂直居中 */
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.number {
|
||||
font-size: 27px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.starmap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius-2);
|
||||
}
|
||||
|
||||
.starmap iframe {
|
||||
position: absolute;
|
||||
top: -150px; /* 根据需要调整裁剪位置 */
|
||||
left: -40px; /* 根据需要调整裁剪位置 */;
|
||||
width: calc(100% + 80px); /* 根据需要调整裁剪宽度 */
|
||||
height: calc(100% + 300px); /* 根据需要调整裁剪高度 */
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
/* PC模式下的样式 */
|
||||
.stats-bar {
|
||||
flex-direction: row;
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
.stats-info {
|
||||
width: 40%;
|
||||
margin: 10px 30px 30px 30px;
|
||||
}
|
||||
|
||||
.starmap {
|
||||
width: 60%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.starmap iframe {
|
||||
position: absolute;
|
||||
top: -130px; /* 根据需要调整裁剪位置 */
|
||||
left: -60px; /* 根据需要调整裁剪位置 */;
|
||||
width: calc(100% + 120px); /* 根据需要调整裁剪宽度 */
|
||||
height: calc(100% + 280px); /* 根据需要调整裁剪高度 */
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
0
docs/.vuepress/public/js/get_data_cn.js → docs/components/Tabs.vue
Normal file → Executable file
67
docs/components/ToggleSwitch.vue
Executable file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<label class="switch">
|
||||
<input type="checkbox" :checked="modelValue" @change="updateValue($event.target.checked)">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const updateValue = (value: boolean) => {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .4s;
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(26px); /* 调整为 26px 以确保对齐 */
|
||||
}
|
||||
</style>
|
11
docs/components/TryLiteyukiWindow.vue
Executable file
@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
4
docs/components/scripts/const.ts
Executable file
@ -0,0 +1,4 @@
|
||||
export const platformBaseURL = "https://github.com/"
|
||||
export const repoPath = "LiteyukiStudio/LiteyukiBot"
|
||||
|
||||
export const repoURL = `${platformBaseURL}${repoPath}`
|
112
docs/components/scripts/i18n.ts
Executable file
@ -0,0 +1,112 @@
|
||||
import {ref} from "vue";
|
||||
|
||||
import {useData} from "vitepress";
|
||||
|
||||
const i18nData = {
|
||||
en: {
|
||||
stats: 'Stats',
|
||||
online: 'Online',
|
||||
offline: 'Offline',
|
||||
total: 'Total',
|
||||
fetching: 'Fetching',
|
||||
stars: 'Stars',
|
||||
forks: 'Forks',
|
||||
issues: 'Issues',
|
||||
prs: 'Pull Requests',
|
||||
visitors: 'Visitors',
|
||||
size: 'Size',
|
||||
plugins: 'Plugins',
|
||||
resources: 'Resources',
|
||||
pluginStore: 'Plugin Store',
|
||||
pluginStoreDesc: 'Content from the LightSnow Plugin Store, LightSnow supports NoneBot through the lpnonebot plugin, and references some NoneBot plugins',
|
||||
liteyukiOnly: 'Liteyuki Only',
|
||||
search: 'Search',
|
||||
resourceStore: 'Resources Store',
|
||||
thx_contributors: 'Thanks the following contributors!',
|
||||
easterEgg: 'Congratulations on finding the Easter egg!',
|
||||
|
||||
publishPlugin: 'Publish Plugin',
|
||||
publishRes: 'Publish Resource',
|
||||
closeButtonText: 'Close',
|
||||
submitButtonText: 'Submit',
|
||||
|
||||
resName: 'Name',
|
||||
resDesc: 'Description',
|
||||
resAuthor: 'Author',
|
||||
resLink: 'Download Link',
|
||||
resHomepage: 'Homepage',
|
||||
|
||||
resNameText: 'Example: Kawaii Style Theme',
|
||||
resDescText: 'Example: A kawaii style and color theme',
|
||||
resAuthorText: 'Usually the github username, Example: yanyongyu',
|
||||
resLinkText: 'Direct download link, usually zip package link',
|
||||
resHomepageText: 'Optional, can be the name of the git platform repository"',
|
||||
},
|
||||
zh: {
|
||||
stats: '统计信息',
|
||||
online: '在线',
|
||||
offline: '离线',
|
||||
total: '实例',
|
||||
fetching: '获取中',
|
||||
stars: '星星',
|
||||
forks: '分叉',
|
||||
issues: '议题',
|
||||
prs: '拉取请求',
|
||||
visitors: '访客',
|
||||
size: '大小',
|
||||
plugins: '插件',
|
||||
resources: '主题资源',
|
||||
store: '商店',
|
||||
pluginStore: '插件商店',
|
||||
pluginStoreDesc: '内容来自轻雪插件商店,轻雪通过lpnonebot插件对NoneBot实现支持,引用了部分NoneBot插件',
|
||||
liteyukiOnly: '仅轻雪',
|
||||
search: '搜索',
|
||||
resourceStore: '资源商店',
|
||||
thx_contributors: '感谢以下贡献者!',
|
||||
easterEgg: '恭喜你发现了彩蛋!',
|
||||
|
||||
publishPlugin: '发布插件',
|
||||
publishRes: '发布资源',
|
||||
closeButtonText: '关闭',
|
||||
submitButtonText: '提交',
|
||||
|
||||
resName: '名称',
|
||||
resDesc: '描述',
|
||||
resAuthor: '作者',
|
||||
resLink: '下载链接',
|
||||
resHomepage: '主页',
|
||||
|
||||
resNameText: '示例:可爱风格主题',
|
||||
resDescText: '示例:一个可爱风格和配色的主题',
|
||||
resAuthorText: '通常为github用户名,示例:yanyongyu',
|
||||
resLinkText: '直接下载链接,通常为zip包链接',
|
||||
resHomepageText: '可选,可为git平台仓库名',
|
||||
}
|
||||
}
|
||||
|
||||
let refData = {}
|
||||
|
||||
function getText(lang: string, key: string): string {
|
||||
lang = formatLang(lang);
|
||||
return i18nData[lang][key];
|
||||
}
|
||||
|
||||
export function formatLang(lang: string): string {
|
||||
if (lang.includes('-')) {
|
||||
return lang.split('-')[0];
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
export function updateRefData() {
|
||||
const lang = formatLang(useData().site.value.lang);
|
||||
for (let key in refData) {
|
||||
refData[key].value = getText(lang, key);
|
||||
}
|
||||
}
|
||||
|
||||
export function getTextRef(key: string): any {
|
||||
const lang = formatLang(useData().site.value.lang);
|
||||
refData[key] = getText(lang, key);
|
||||
return refData[key] || key;
|
||||
}
|
182
docs/components/scripts/statsApi.ts
Executable file
@ -0,0 +1,182 @@
|
||||
// URL
|
||||
export const OWNER = "LiteyukiStudio"
|
||||
export const REPO = "LiteyukiBot"
|
||||
const githubAPIUrl = "https://api.github.com"
|
||||
const giteaAPIUrl = "https://git.liteyuki.icu/api/v1"
|
||||
const onlineFetchUrl = "https://api.liteyuki.icu/online";
|
||||
const totalFetchUrl = "https://api.liteyuki.icu/count";
|
||||
const visitRecordUrl = "https://api.liteyuki.icu/visit";
|
||||
const visitCountUrl = "https://api.liteyuki.icu/visit_count";
|
||||
|
||||
export const RepoUrl = `https://github.com/${OWNER}/${REPO}`
|
||||
export const StarMapUrl = "https://starmap.liteyuki.icu"
|
||||
|
||||
type GithubStats = {
|
||||
stars: number;
|
||||
forks: number;
|
||||
watchers: number;
|
||||
issues?: number;
|
||||
prs?: number;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
// 异步接口
|
||||
interface StatsApi {
|
||||
getTotal: () => Promise<number>;
|
||||
getOnline: () => Promise<number>;
|
||||
getGithubStats: () => Promise<GithubStats>;
|
||||
getPluginNum: () => Promise<number>;
|
||||
getResourceNum: () => Promise<number>;
|
||||
getVisitCount: () => Promise<number>;
|
||||
}
|
||||
|
||||
|
||||
export type {GithubStats};
|
||||
|
||||
async function getGiteaStats() {
|
||||
try {
|
||||
const url = `${giteaAPIUrl}/repos/${OWNER}/${REPO}`;
|
||||
console.log(url);
|
||||
const res = await fetch(url);
|
||||
const data = await res.json();
|
||||
return {
|
||||
stars: data.stars_count,
|
||||
forks: data.forks_count,
|
||||
watchers: data.watchers_count,
|
||||
issues: 0,
|
||||
prs: 0,
|
||||
size: data.size,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
stars: -1,
|
||||
forks: -1,
|
||||
watchers: -1,
|
||||
issues: -1,
|
||||
prs: -1,
|
||||
size: -1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function getGithubStats() {
|
||||
try {
|
||||
const res = await fetch(`${githubAPIUrl}/repos/${OWNER}/${REPO}`);
|
||||
const data = await res.json();
|
||||
return {
|
||||
stars: data.stargazers_count,
|
||||
forks: data.forks_count,
|
||||
watchers: data.watchers_count,
|
||||
issues: data.open_issues_count,
|
||||
prs: data.open_issues_count,
|
||||
size: data.size,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
stars: -1,
|
||||
forks: -1,
|
||||
watchers: -1,
|
||||
issues: -1,
|
||||
prs: -1,
|
||||
size: -1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function getRepoStats() {
|
||||
// 两个接口各数据,加和返回
|
||||
const githubStats = await getGithubStats();
|
||||
const giteaStats = await getGiteaStats();
|
||||
return {
|
||||
stars: githubStats.stars + giteaStats.stars,
|
||||
forks: githubStats.forks + giteaStats.forks,
|
||||
watchers: githubStats.watchers + giteaStats.watchers,
|
||||
issues: githubStats.issues + giteaStats.issues,
|
||||
prs: githubStats.prs + giteaStats.prs,
|
||||
size: githubStats.size + giteaStats.size,
|
||||
};
|
||||
}
|
||||
|
||||
// 实现接口
|
||||
export const statsApi: StatsApi = {
|
||||
getTotal: async () => {
|
||||
try {
|
||||
const res = await fetch(totalFetchUrl);
|
||||
const data = await res.json();
|
||||
return data.register;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
getOnline: async () => {
|
||||
try {
|
||||
const res = await fetch(onlineFetchUrl);
|
||||
const data = await res.json();
|
||||
return data.online;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
getGithubStats: getRepoStats,
|
||||
getPluginNum: async () => {
|
||||
try {
|
||||
const res = await fetch('/plugins.json');
|
||||
const data = await res.json();
|
||||
return data.length;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
getResourceNum: async () => {
|
||||
try {
|
||||
const res = await fetch('/resources.json');
|
||||
const data = await res.json();
|
||||
return data.length;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
getVisitCount: async () => {
|
||||
try {
|
||||
const res = await fetch(visitCountUrl);
|
||||
const data = await res.json();
|
||||
return data.count;
|
||||
} catch (e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getDeviceId(): string {
|
||||
// 用户每次访问时生成一个唯一的设备ID,储存在localStorage中,用于统计用户数量
|
||||
const deviceIdKey = 'deviceId';
|
||||
let deviceId = localStorage.getItem(deviceIdKey);
|
||||
|
||||
if (!deviceId) {
|
||||
deviceId = generateUUID();
|
||||
localStorage.setItem(deviceIdKey, deviceId);
|
||||
}
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
export async function uploadVisitRecord() {
|
||||
const deviceId = getDeviceId();
|
||||
try {
|
||||
await fetch(visitRecordUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: new URLSearchParams({'device_id': deviceId}).toString(),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to upload visit record:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function generateUUID(): string {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
---
|
||||
title: 项目部署
|
||||
index: false
|
||||
icon: laptop-code
|
||||
category: 部署
|
||||
---
|
||||
|
||||
<Catalog />
|
@ -1,9 +0,0 @@
|
||||
# note
|
||||
开发者选项
|
||||
allow_update: true # 是否允许更新
|
||||
log_level: "INFO" # 日志等级
|
||||
log_icon: true # 是否显示日志等级图标(某些控制台字体不可用)
|
||||
auto_report: true # 是否自动上报问题给轻雪服务器
|
||||
auto_update: true # 是否自动更新轻雪,每天4点检查更新
|
||||
safe_mode: false # 安全模式,开启后将不会加载任何第三方插件
|
||||
dev_mode: false # 开发者模式,开启后将会启动看门狗
|
@ -1,78 +0,0 @@
|
||||
---
|
||||
title: 配置
|
||||
icon: cog
|
||||
order: 2
|
||||
category: 使用指南
|
||||
tag:
|
||||
- 配置
|
||||
- 部署
|
||||
---
|
||||
|
||||
轻雪支持`yaml`、`json`和`toml`作为配置文件,取决于你个人的喜好
|
||||
|
||||
首次运行后生成`config.yml`和`config`目录,你可修改配置项后重启轻雪,绝大多数情况下,你只需要修改`superusers`及`nickname`字段即可
|
||||
|
||||
启动时会加载项目目录下`config.yml/yaml/json/toml`和`config`目录下的所有配置文件,你可在`config`目录下创建多个配置文件,轻雪会自动合并这些配置文件
|
||||
|
||||
## **基础配置项**
|
||||
|
||||
```yaml
|
||||
nonebot:
|
||||
# Nonebot机器人的配置,以前的最外层配置项仍可为Nonebot服务,但是部分内容会被覆盖,请尽快迁移
|
||||
command_start: [ "/", "" ] # 指令前缀,若没有""空命令头,请开启alconna_use_command_start保证alconna解析正常
|
||||
host: 127.0.0.1 # 监听地址,默认为本机,若要接收外部请求请填写0.0.0.0
|
||||
port: 20216 # 绑定端口
|
||||
nickname: [ "liteyuki" ] # 机器人昵称列表
|
||||
superusers: [ "1919810" ] # 超级用户列表
|
||||
liteyuki:
|
||||
# 写在外层的配置项将会被覆盖,建议迁移到liteyuki下
|
||||
log_level: "INFO" # 日志等级
|
||||
log_icon: true # 是否显示日志等级图标(某些控制台字体不可用)
|
||||
auto_report: true # 是否自动上报问题给轻雪服务器
|
||||
auto_update: true # 是否自动更新轻雪,每天4点检查更新
|
||||
plugins: [ ] # 轻雪插件列表
|
||||
plugin_dirs: [ ] # 轻雪插件目录列表
|
||||
```
|
||||
|
||||
## **其他配置**
|
||||
|
||||
以下为默认值,如需自定义请手动添加
|
||||
|
||||
```yaml
|
||||
# 高级NoneBot配置
|
||||
nonebot:
|
||||
onebot_access_token: "" # 访问令牌,对公开放时建议设置
|
||||
default_language: "zh-CN" # 默认语言
|
||||
alconna_auto_completion: false # alconna是否自动补全指令,默认false,建议开启
|
||||
safe_mode: false # 安全模式,开启后将不会加载任何第三方NoneBot插件
|
||||
# 其他Nonebot插件的配置项
|
||||
custom_config_1: "custom_value1"
|
||||
custom_config_2: "custom_value2"
|
||||
|
||||
# 开发者选项
|
||||
liteyuki:
|
||||
allow_update: true # 是否允许更新
|
||||
debug: false # 轻雪调试,开启会自动重载Bot或者资源,其他插件自带的调试功能也将开启
|
||||
dev_mode: false # 开发者模式,开启后将会启动监视者,监视文件变化并自动重载
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> 如果要使用NoneBot和dotenv配置文件,请自行创建`.env.{ENVIRONMENT}`,并在`config.yml`中添加`nonebot.environment:{ENVIRONMENT}`字段
|
||||
|
||||
## **与NoneBot对接的OneBot实现端配置**
|
||||
|
||||
生产环境中推荐反向WebSocket
|
||||
不同的实现端给出的字段可能不同,但是基本上都是一样的,这里给出一个参考值
|
||||
|
||||
| 字段 | 参考值 | 说明 |
|
||||
|-------------|------------------------------------|----------------------------------|
|
||||
| 协议 | 反向WebSocket | 推荐使用反向ws协议进行通信,即轻雪作为服务端 |
|
||||
| 地址 | ws://127.0.0.1:20216/onebot/v11/ws | 地址取决于配置文件,本机默认为`127.0.0.1:20216` |
|
||||
| AccessToken | `""` | 如果你给轻雪配置了`AccessToken`,请在此填写相同的值 |
|
||||
|
||||
## **其他**
|
||||
|
||||
- 要使用其他通信方式请访问[OneBot Adapter](https://onebot.adapters.nonebot.dev/)获取详细信息
|
||||
- 轻雪不局限于OneBot适配器,你可以使用NoneBot2支持的任何适配器
|
@ -1,58 +0,0 @@
|
||||
---
|
||||
title: 答疑
|
||||
icon: question
|
||||
order: 3
|
||||
category: 使用指南
|
||||
tag:
|
||||
- 配置
|
||||
- 部署
|
||||
---
|
||||
|
||||
## **常见问题**
|
||||
|
||||
- 设备上Python环境太乱了,pip和python不对应怎么办?
|
||||
- 请使用`/path/to/python -m pip install -r requirements.txt`来安装依赖,
|
||||
然后用`/path/to/python main.py`来启动Bot,
|
||||
其中`/path/to/python`是你要用来运行Bot的可执行文件
|
||||
|
||||
- 为什么我启动后机器人没有反应?
|
||||
- 请检查配置文件的`command_start`或`superusers`,确认你有权限使用命令并按照正确的命令发送
|
||||
- 确认命令头没有和`nickname{}`冲突,例如一个命令是`help`,但是`Bot`昵称有一个`help`,那么将会被解析为nickname而不是命令
|
||||
|
||||
- 更新轻雪失败,报错`InvalidGitRepositoryError`
|
||||
- 请正确安装`Git`,并使用克隆而非直接下载的方式部署轻雪
|
||||
|
||||
- 怎么登录聊天平台,例如QQ?
|
||||
- 你有这个问题说明你不是很了解这个项目,本项目不负责实现登录功能,只负责处理和回应消息,登录功能由实现端(协议端)提供,
|
||||
实现端本身不负责处理响应逻辑,将消息按照OneBot标准处理好上报给轻雪
|
||||
你需要使用Onebot标准的实现端来连接到轻雪并将消息上报给轻雪,下面已经列出一些推荐的实现端
|
||||
- `Playwright`安装失败
|
||||
- 输入`playwright install`安装浏览器
|
||||
- 有的插件安装后报错无法启动
|
||||
- 请先查阅插件文档,确认插件必要配置项完好后,仍然出现问题,请联系插件作者或在安全模式`safe_mode: true`下启动轻雪,在安全模式下你可以使用`npm uninstall`卸载问题插件
|
||||
- 其他问题
|
||||
-
|
||||
加入QQ群[775840726](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=SzmDYbfR6jY94o9KFNon7AwelRyI6M_u&authKey=ygeBdEmdFNyCWuNR4w0M1M8%2B5oDg7k%2FDfN0tzBkYcnbB%2FGHNnlVEnCIGbdftsnn7&noverify=0&group_code=775840726)
|
||||
|
||||
## **推荐方案(QQ)**
|
||||
|
||||
1. [Lagrange.OneBot](https://github.com/KonataDev/Lagrange.Core),基于NTQQ的OneBot实现,目前Markdown消息支持Lagrange
|
||||
2. [LLOneBot](https://github.com/LLOneBot/LLOneBot),NTQQ的OneBot插件,需要安装NTQQ
|
||||
3. [OpenShamrock](https://github.com/whitechi73/OpenShamrock),基于Lsposed的OneBot11实现
|
||||
4. [TRSS-Yunzai](https://github.com/TimeRainStarSky/Yunzai),基于`node.js`,可使用`ws-plugin`进行通信
|
||||
5. [go-cqhttp](https://github.com/Mrs4s/go-cqhttp),`go`语言实现的OneBot11实现端,目前可用性较低
|
||||
6. [Gensokyo](https://github.com/Hoshinonyaruko/Gensokyo),基于 OneBot QQ官方机器人Api Golang 原生实现,需要官方机器人权限
|
||||
7. 人工实现的`Onebot`协议,自己整一个WebSocket客户端,看着QQ的消息,然后给轻雪传输数据
|
||||
|
||||
## **推荐方案(Minecraft)**
|
||||
|
||||
1. [MinecraftOneBot](https://github.com/snowykami/MinecraftOnebot),我们专门为Minecraft开发的服务器Bot,支持OneBotV11标准
|
||||
|
||||
使用其他项目连接请先自行查阅文档,若有困难请联系对应开发者而不是Liteyuki的开发者
|
||||
|
||||
## **鸣谢**
|
||||
|
||||
- [Nonebot2](https://nonebot.dev)提供的框架支持
|
||||
- [nonebot-plugin-htmlrender](https://github.com/kexue-z/nonebot-plugin-htmlrender/tree/master)提供的渲染功能
|
||||
- [nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna)提供的命令解析功能
|
||||
- [MiSans](https://hyperos.mi.com/font/zh/),[MapleMono](https://gitee.com/mirrors/Maple-Mono)提供的字体,且遵守了相关字体开源协议
|
@ -1,60 +0,0 @@
|
||||
---
|
||||
title: 安装
|
||||
icon: download
|
||||
order: 1
|
||||
category: 使用指南
|
||||
tag:
|
||||
- 安装
|
||||
---
|
||||
|
||||
## **开始安装**
|
||||
|
||||
### **常规部署**
|
||||
|
||||
1. 安装 [`Git`](https://git-scm.com/download/) 和 [`Python3.10+`](https://www.python.org/downloads/release/python-31010/) 环境
|
||||
|
||||
```bash
|
||||
# 克隆项目到本地,轻雪使用Git进行版本管理,该步骤为必要项
|
||||
git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1
|
||||
# 切换到Bot目录下
|
||||
cd LiteyukiBot
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
# 启动Bot
|
||||
python main.py
|
||||
```
|
||||
|
||||
> [!tip]
|
||||
> 推荐使用虚拟环境来运行轻雪,以避免依赖冲突,你可以使用`python -m venv .venv`来创建虚拟环境,然后使用`.venv\Scripts\activate`来激活虚拟环境(Linux下使用`source .venv/bin/activate`激活)
|
||||
|
||||
### **使用Docker构建镜像部署**
|
||||
|
||||
1. 安装 [`Docker`](https://docs.docker.com/get-docker/)
|
||||
2. 克隆项目 `git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1`
|
||||
3. 进入轻雪目录 `cd LiteyukiBot`
|
||||
4. 构建镜像 `docker build -t liteyukibot .`
|
||||
5. 启动容器 `docker run -p 20216:20216 -v $(pwd):/liteyukibot -v $(pwd)/.cache:/root/.cache liteyukibot`
|
||||
|
||||
> [!tip]
|
||||
> Windows请使用项目绝对目录`/path/to/LiteyukiBot`代替`$(pwd)` <br>
|
||||
> 若你修改了端口号请将`20216:20216`中的`20216`替换为你的端口号
|
||||
|
||||
### **使用TRSS Scripts部署**
|
||||
[TRSS_Liteyuki轻雪机器人管理脚本](https://timerainstarsky.github.io/TRSS_Liteyuki/),该功能由TRSS提供支持,不是LiteyukiBot官方提供的功能,推荐使用`Arch Linux`
|
||||
|
||||
|
||||
## **设备要求**
|
||||
|
||||
- Windows系统版本最低`Windows10+`/`Windows Server 2019+`
|
||||
- Linux系统要支持Python3.10+,推荐`Ubuntu 20.04+`(~~别用你那b CentOS~~)
|
||||
- CPU: 至少`1vCPU`
|
||||
- 内存: Bot无其他插件会占用`300~500MB`,包括`chromium` 及 `node`等进程,其他插件占用视具体插件而定,建议`1GB`以上
|
||||
- 硬盘: 至少`1GB`空间
|
||||
|
||||
> [!warning]
|
||||
> 如果设备上有多个环境,请使用`path/to/python -m pip install -r requirements.txt`来安装依赖,`path/to/python`为你的Python可执行文件路径
|
||||
|
||||
> [!warning]
|
||||
> 轻雪的更新功能依赖Git,如果你没有安装Git直接下载源代码运行,你将无法使用更新功能
|
||||
|
||||
#### 其他问题请移步至[答疑](/deployment/fandq)
|
@ -1,8 +0,0 @@
|
||||
---
|
||||
title: 开发及贡献
|
||||
index: false
|
||||
icon: laptop-code
|
||||
category: 开发
|
||||
---
|
||||
|
||||
<Catalog />
|
@ -1,7 +0,0 @@
|
||||
---
|
||||
title: liteyuki
|
||||
index: true
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
@ -1,581 +0,0 @@
|
||||
---
|
||||
title: liteyuki.bot
|
||||
index: true
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***def*** `get_bot() -> LiteyukiBot`
|
||||
|
||||
获取轻雪实例
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
LiteyukiBot: 当前的轻雪实例
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_bot() -> LiteyukiBot:
|
||||
"""
|
||||
获取轻雪实例
|
||||
|
||||
Returns:
|
||||
LiteyukiBot: 当前的轻雪实例
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
if _BOT_INSTANCE is None:
|
||||
raise RuntimeError('Liteyuki instance not initialized.')
|
||||
return _BOT_INSTANCE
|
||||
else:
|
||||
raise RuntimeError("Can't get bot instance in sub process.")
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `get_config(key: str, default: Any) -> Any`
|
||||
|
||||
获取配置
|
||||
|
||||
Args:
|
||||
|
||||
key: 配置键
|
||||
|
||||
default: 默认值
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
Any: 配置值
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_config(key: str, default: Any=None) -> Any:
|
||||
"""
|
||||
获取配置
|
||||
Args:
|
||||
key: 配置键
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
Any: 配置值
|
||||
"""
|
||||
return get_bot().config.get(key, default)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `get_config_with_compat(key: str, compat_keys: tuple[str], default: Any) -> Any`
|
||||
|
||||
获取配置,兼容旧版本
|
||||
|
||||
Args:
|
||||
|
||||
key: 配置键
|
||||
|
||||
compat_keys: 兼容键
|
||||
|
||||
default: 默认值
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
Any: 配置值
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_config_with_compat(key: str, compat_keys: tuple[str], default: Any=None) -> Any:
|
||||
"""
|
||||
获取配置,兼容旧版本
|
||||
Args:
|
||||
key: 配置键
|
||||
compat_keys: 兼容键
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
Any: 配置值
|
||||
"""
|
||||
if key in get_bot().config:
|
||||
return get_bot().config[key]
|
||||
for compat_key in compat_keys:
|
||||
if compat_key in get_bot().config:
|
||||
logger.warning(f'Config key "{compat_key}" will be deprecated, use "{key}" instead.')
|
||||
return get_bot().config[compat_key]
|
||||
return default
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `print_logo() -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def print_logo():
|
||||
print('\x1b[34m' + '\n __ ______ ________ ________ __ __ __ __ __ __ ______ \n / | / |/ |/ |/ \\ / |/ | / |/ | / |/ |\n $$ | $$$$$$/ $$$$$$$$/ $$$$$$$$/ $$ \\ /$$/ $$ | $$ |$$ | /$$/ $$$$$$/ \n $$ | $$ | $$ | $$ |__ $$ \\/$$/ $$ | $$ |$$ |/$$/ $$ | \n $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |$$ $$< $$ | \n $$ | $$ | $$ | $$$$$/ $$$$/ $$ | $$ |$$$$$ \\ $$ | \n $$ |_____ _$$ |_ $$ | $$ |_____ $$ | $$ \\__$$ |$$ |$$ \\ _$$ |_ \n $$ |/ $$ | $$ | $$ | $$ | $$ $$/ $$ | $$ |/ $$ |\n $$$$$$$$/ $$$$$$/ $$/ $$$$$$$$/ $$/ $$$$$$/ $$/ $$/ $$$$$$/ \n ' + '\x1b[0m')
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `LiteyukiBot`
|
||||
|
||||
|
||||
|
||||
###   ***def*** `__init__(self) -> None`
|
||||
|
||||
 初始化轻雪实例
|
||||
|
||||
Args:
|
||||
|
||||
*args:
|
||||
|
||||
**kwargs: 配置
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
"""
|
||||
初始化轻雪实例
|
||||
Args:
|
||||
*args:
|
||||
**kwargs: 配置
|
||||
|
||||
"""
|
||||
'常规操作'
|
||||
print_logo()
|
||||
global _BOT_INSTANCE
|
||||
_BOT_INSTANCE = self
|
||||
'配置'
|
||||
self.config: dict[str, Any] = kwargs
|
||||
'初始化'
|
||||
self.init(**self.config)
|
||||
logger.info('Liteyuki is initializing...')
|
||||
'生命周期管理'
|
||||
self.lifespan = Lifespan()
|
||||
self.process_manager: ProcessManager = ProcessManager(lifespan=self.lifespan)
|
||||
'事件循环'
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(self.loop)
|
||||
self.stop_event = threading.Event()
|
||||
self.call_restart_count = 0
|
||||
'加载插件加载器'
|
||||
load_plugin('liteyuki.plugins.plugin_loader')
|
||||
'信号处理'
|
||||
signal.signal(signal.SIGINT, self._handle_exit)
|
||||
signal.signal(signal.SIGTERM, self._handle_exit)
|
||||
atexit.register(self.process_manager.terminate_all)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `run(self) -> None`
|
||||
|
||||
 启动逻辑
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def run(self):
|
||||
"""
|
||||
启动逻辑
|
||||
"""
|
||||
self.lifespan.before_start()
|
||||
self.process_manager.start_all()
|
||||
self.lifespan.after_start()
|
||||
self.keep_alive()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `keep_alive(self) -> None`
|
||||
|
||||
 保持轻雪运行
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def keep_alive(self):
|
||||
"""
|
||||
保持轻雪运行
|
||||
Returns:
|
||||
|
||||
"""
|
||||
try:
|
||||
while not self.stop_event.is_set():
|
||||
time.sleep(0.5)
|
||||
except KeyboardInterrupt:
|
||||
logger.info('Liteyuki is stopping...')
|
||||
self.stop()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `restart(self, delay: int) -> None`
|
||||
|
||||
 重启轻雪本体
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def restart(self, delay: int=0):
|
||||
"""
|
||||
重启轻雪本体
|
||||
Returns:
|
||||
|
||||
"""
|
||||
if self.call_restart_count < 1:
|
||||
executable = sys.executable
|
||||
args = sys.argv
|
||||
logger.info('Restarting LiteyukiBot...')
|
||||
time.sleep(delay)
|
||||
if platform.system() == 'Windows':
|
||||
cmd = 'start'
|
||||
elif platform.system() == 'Linux':
|
||||
cmd = 'nohup'
|
||||
elif platform.system() == 'Darwin':
|
||||
cmd = 'open'
|
||||
else:
|
||||
cmd = 'nohup'
|
||||
self.process_manager.terminate_all()
|
||||
threading.Thread(target=os.system, args=(f"{cmd} {executable} {' '.join(args)}",)).start()
|
||||
sys.exit(0)
|
||||
self.call_restart_count += 1
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `restart_process(self, name: Optional[str]) -> None`
|
||||
|
||||
 停止轻雪
|
||||
|
||||
Args:
|
||||
|
||||
name: 进程名称, 默认为None, 所有进程
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def restart_process(self, name: Optional[str]=None):
|
||||
"""
|
||||
停止轻雪
|
||||
Args:
|
||||
name: 进程名称, 默认为None, 所有进程
|
||||
Returns:
|
||||
"""
|
||||
self.lifespan.before_process_shutdown()
|
||||
self.lifespan.before_process_shutdown()
|
||||
if name is not None:
|
||||
chan_active = get_channel(f'{name}-active')
|
||||
chan_active.send(1)
|
||||
else:
|
||||
for process_name in self.process_manager.processes:
|
||||
chan_active = get_channel(f'{process_name}-active')
|
||||
chan_active.send(1)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `init(self) -> None`
|
||||
|
||||
 初始化轻雪, 自动调用
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def init(self, *args, **kwargs):
|
||||
"""
|
||||
初始化轻雪, 自动调用
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self.init_logger()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `init_logger(self) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def init_logger(self):
|
||||
init_log(config=self.config)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `stop(self) -> None`
|
||||
|
||||
 停止轻雪
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def stop(self):
|
||||
"""
|
||||
停止轻雪
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self.stop_event.set()
|
||||
self.loop.stop()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_start(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册启动前的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_start(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册启动前的函数
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_before_start(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_start(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册启动后的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_start(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册启动后的函数
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_after_start(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_shutdown(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册停止后的函数:未实现
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_shutdown(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册停止后的函数:未实现
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_after_shutdown(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册进程停止前的函数,为子进程停止时调用
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_process_shutdown(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册进程停止前的函数,为子进程停止时调用
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_before_process_shutdown(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_process_restart(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册进程重启前的函数,为子进程重启时调用
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_process_restart(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册进程重启前的函数,为子进程重启时调用
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_before_process_restart(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_restart(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册重启后的函数:未实现
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_restart(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册重启后的函数:未实现
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_after_restart(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_nonebot_init(self, func: LIFESPAN_FUNC) -> None`
|
||||
|
||||
 注册nonebot初始化后的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_nonebot_init(self, func: LIFESPAN_FUNC):
|
||||
"""
|
||||
注册nonebot初始化后的函数
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self.lifespan.on_after_nonebot_init(func)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***var*** `executable = sys.executable`
|
||||
|
||||
|
||||
|
||||
### ***var*** `args = sys.argv`
|
||||
|
||||
|
||||
|
||||
### ***var*** `chan_active = get_channel(f'{name}-active')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `cmd = 'start'`
|
||||
|
||||
|
||||
|
||||
### ***var*** `chan_active = get_channel(f'{process_name}-active')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `cmd = 'nohup'`
|
||||
|
||||
|
||||
|
||||
### ***var*** `cmd = 'open'`
|
||||
|
||||
|
||||
|
||||
### ***var*** `cmd = 'nohup'`
|
||||
|
||||
|
||||
|
@ -1,450 +0,0 @@
|
||||
---
|
||||
title: liteyuki.bot.lifespan
|
||||
order: 1
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***def*** `run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC]) -> None`
|
||||
|
||||
运行函数
|
||||
|
||||
Args:
|
||||
|
||||
funcs:
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
def run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC], *args, **kwargs) -> None:
|
||||
"""
|
||||
运行函数
|
||||
Args:
|
||||
funcs:
|
||||
Returns:
|
||||
"""
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
tasks = []
|
||||
for func in funcs:
|
||||
if is_coroutine_callable(func):
|
||||
tasks.append(func(*args, **kwargs))
|
||||
else:
|
||||
tasks.append(async_wrapper(func)(*args, **kwargs))
|
||||
loop.run_until_complete(asyncio.gather(*tasks))
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `Lifespan`
|
||||
|
||||
|
||||
|
||||
###   ***def*** `__init__(self) -> None`
|
||||
|
||||
 轻雪生命周期管理,启动、停止、重启
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
轻雪生命周期管理,启动、停止、重启
|
||||
"""
|
||||
self.life_flag: int = 0
|
||||
self._before_start_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._after_start_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._before_process_shutdown_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._after_shutdown_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._before_process_restart_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._after_restart_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._after_nonebot_init_funcs: list[LIFESPAN_FUNC] = []
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***@staticmethod***
|
||||
###   ***def*** `run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC]) -> None`
|
||||
|
||||
 运行函数
|
||||
|
||||
Args:
|
||||
|
||||
funcs:
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
def run_funcs(funcs: list[LIFESPAN_FUNC | PROCESS_LIFESPAN_FUNC], *args, **kwargs) -> None:
|
||||
"""
|
||||
运行函数
|
||||
Args:
|
||||
funcs:
|
||||
Returns:
|
||||
"""
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
tasks = []
|
||||
for func in funcs:
|
||||
if is_coroutine_callable(func):
|
||||
tasks.append(func(*args, **kwargs))
|
||||
else:
|
||||
tasks.append(async_wrapper(func)(*args, **kwargs))
|
||||
loop.run_until_complete(asyncio.gather(*tasks))
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册启动时的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册启动时的函数
|
||||
Args:
|
||||
func:
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
"""
|
||||
self._before_start_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册启动时的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_start(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册启动时的函数
|
||||
Args:
|
||||
func:
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
"""
|
||||
self._after_start_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册停止前的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_process_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册停止前的函数
|
||||
Args:
|
||||
func:
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
"""
|
||||
self._before_process_shutdown_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册停止后的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_shutdown(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册停止后的函数
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
"""
|
||||
self._after_shutdown_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_before_process_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册重启时的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_before_process_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册重启时的函数
|
||||
Args:
|
||||
func:
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
"""
|
||||
self._before_process_restart_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC`
|
||||
|
||||
 注册重启后的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
LIFESPAN_FUNC:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_restart(self, func: LIFESPAN_FUNC) -> LIFESPAN_FUNC:
|
||||
"""
|
||||
注册重启后的函数
|
||||
Args:
|
||||
func:
|
||||
Returns:
|
||||
LIFESPAN_FUNC:
|
||||
"""
|
||||
self._after_restart_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_after_nonebot_init(self, func: Any) -> None`
|
||||
|
||||
 注册 NoneBot 初始化后的函数
|
||||
|
||||
Args:
|
||||
|
||||
func:
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_after_nonebot_init(self, func):
|
||||
"""
|
||||
注册 NoneBot 初始化后的函数
|
||||
Args:
|
||||
func:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self._after_nonebot_init_funcs.append(func)
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `before_start(self) -> None`
|
||||
|
||||
 启动前
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def before_start(self) -> None:
|
||||
"""
|
||||
启动前
|
||||
Returns:
|
||||
"""
|
||||
logger.debug('Running before_start functions')
|
||||
self.run_funcs(self._before_start_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `after_start(self) -> None`
|
||||
|
||||
 启动后
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def after_start(self) -> None:
|
||||
"""
|
||||
启动后
|
||||
Returns:
|
||||
"""
|
||||
logger.debug('Running after_start functions')
|
||||
self.run_funcs(self._after_start_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `before_process_shutdown(self) -> None`
|
||||
|
||||
 停止前
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def before_process_shutdown(self) -> None:
|
||||
"""
|
||||
停止前
|
||||
Returns:
|
||||
"""
|
||||
logger.debug('Running before_shutdown functions')
|
||||
self.run_funcs(self._before_process_shutdown_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `after_shutdown(self) -> None`
|
||||
|
||||
 停止后
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def after_shutdown(self) -> None:
|
||||
"""
|
||||
停止后
|
||||
Returns:
|
||||
"""
|
||||
logger.debug('Running after_shutdown functions')
|
||||
self.run_funcs(self._after_shutdown_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `before_process_restart(self) -> None`
|
||||
|
||||
 重启前
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def before_process_restart(self) -> None:
|
||||
"""
|
||||
重启前
|
||||
Returns:
|
||||
"""
|
||||
logger.debug('Running before_restart functions')
|
||||
self.run_funcs(self._before_process_restart_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `after_restart(self) -> None`
|
||||
|
||||
 重启后
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def after_restart(self) -> None:
|
||||
"""
|
||||
重启后
|
||||
Returns:
|
||||
|
||||
"""
|
||||
logger.debug('Running after_restart functions')
|
||||
self.run_funcs(self._after_restart_funcs)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***var*** `tasks = []`
|
||||
|
||||
|
||||
|
||||
### ***var*** `loop = asyncio.get_event_loop()`
|
||||
|
||||
|
||||
|
||||
### ***var*** `loop = asyncio.new_event_loop()`
|
||||
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
---
|
||||
title: liteyuki.comm
|
||||
index: true
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
@ -1,427 +0,0 @@
|
||||
---
|
||||
title: liteyuki.comm.channel
|
||||
order: 1
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***def*** `set_channel(name: str, channel: Channel) -> None`
|
||||
|
||||
设置通道实例
|
||||
|
||||
Args:
|
||||
|
||||
name: 通道名称
|
||||
|
||||
channel: 通道实例
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def set_channel(name: str, channel: Channel):
|
||||
"""
|
||||
设置通道实例
|
||||
Args:
|
||||
name: 通道名称
|
||||
channel: 通道实例
|
||||
"""
|
||||
if not isinstance(channel, Channel):
|
||||
raise TypeError(f'channel_ must be an instance of Channel, {type(channel)} found')
|
||||
if IS_MAIN_PROCESS:
|
||||
_channel[name] = channel
|
||||
else:
|
||||
channel_deliver_passive_channel.send(('set_channel', {'name': name, 'channel_': channel}))
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `set_channels(channels: dict[str, Channel]) -> None`
|
||||
|
||||
设置通道实例
|
||||
|
||||
Args:
|
||||
|
||||
channels: 通道名称
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def set_channels(channels: dict[str, Channel]):
|
||||
"""
|
||||
设置通道实例
|
||||
Args:
|
||||
channels: 通道名称
|
||||
"""
|
||||
for name, channel in channels.items():
|
||||
set_channel(name, channel)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `get_channel(name: str) -> Channel`
|
||||
|
||||
获取通道实例
|
||||
|
||||
Args:
|
||||
|
||||
name: 通道名称
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_channel(name: str) -> Channel:
|
||||
"""
|
||||
获取通道实例
|
||||
Args:
|
||||
name: 通道名称
|
||||
Returns:
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
return _channel[name]
|
||||
else:
|
||||
recv_chan = Channel[Channel[Any]]('recv_chan')
|
||||
channel_deliver_passive_channel.send(('get_channel', {'name': name, 'recv_chan': recv_chan}))
|
||||
return recv_chan.receive()
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `get_channels() -> dict[str, Channel]`
|
||||
|
||||
获取通道实例
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_channels() -> dict[str, Channel]:
|
||||
"""
|
||||
获取通道实例
|
||||
Returns:
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
return _channel
|
||||
else:
|
||||
recv_chan = Channel[dict[str, Channel[Any]]]('recv_chan')
|
||||
channel_deliver_passive_channel.send(('get_channels', {'recv_chan': recv_chan}))
|
||||
return recv_chan.receive()
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_set_channel(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'set_channel')
|
||||
def on_set_channel(data: tuple[str, dict[str, Any]]):
|
||||
name, channel = (data[1]['name'], data[1]['channel_'])
|
||||
set_channel(name, channel)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_get_channel(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channel')
|
||||
def on_get_channel(data: tuple[str, dict[str, Any]]):
|
||||
name, recv_chan = (data[1]['name'], data[1]['recv_chan'])
|
||||
recv_chan.send(get_channel(name))
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_get_channels(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@channel_deliver_passive_channel.on_receive(filter_func=lambda data: data[0] == 'get_channels')
|
||||
def on_get_channels(data: tuple[str, dict[str, Any]]):
|
||||
recv_chan = data[1]['recv_chan']
|
||||
recv_chan.send(get_channels())
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `decorator(func: Callable[[T], Any]) -> Callable[[T], Any]`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def decorator(func: Callable[[T], Any]) -> Callable[[T], Any]:
|
||||
global _func_id
|
||||
|
||||
async def wrapper(data: T) -> Any:
|
||||
if filter_func is not None:
|
||||
if is_coroutine_callable(filter_func):
|
||||
if not await filter_func(data):
|
||||
return
|
||||
elif not filter_func(data):
|
||||
return
|
||||
if is_coroutine_callable(func):
|
||||
return await func(data)
|
||||
else:
|
||||
return func(data)
|
||||
_callback_funcs[_func_id] = wrapper
|
||||
if IS_MAIN_PROCESS:
|
||||
self._on_main_receive_funcs.append(_func_id)
|
||||
else:
|
||||
self._on_sub_receive_funcs.append(_func_id)
|
||||
_func_id += 1
|
||||
return func
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***async def*** `wrapper(data: T) -> Any`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
async def wrapper(data: T) -> Any:
|
||||
if filter_func is not None:
|
||||
if is_coroutine_callable(filter_func):
|
||||
if not await filter_func(data):
|
||||
return
|
||||
elif not filter_func(data):
|
||||
return
|
||||
if is_coroutine_callable(func):
|
||||
return await func(data)
|
||||
else:
|
||||
return func(data)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `Channel(Generic[T])`
|
||||
|
||||
通道类,可以在进程间和进程内通信,双向但同时只能有一个发送者和一个接收者
|
||||
|
||||
有两种接收工作方式,但是只能选择一种,主动接收和被动接收,主动接收使用 `receive` 方法,被动接收使用 `on_receive` 装饰器
|
||||
|
||||
###   ***def*** `__init__(self, _id: str, type_check: Optional[bool]) -> None`
|
||||
|
||||
 初始化通道
|
||||
|
||||
Args:
|
||||
|
||||
_id: 通道ID
|
||||
|
||||
type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self, _id: str, type_check: Optional[bool]=None):
|
||||
"""
|
||||
初始化通道
|
||||
Args:
|
||||
_id: 通道ID
|
||||
type_check: 是否开启类型检查, 若为空,则传入泛型默认开启,否则默认关闭
|
||||
"""
|
||||
self.conn_send, self.conn_recv = Pipe()
|
||||
self._closed = False
|
||||
self._on_main_receive_funcs: list[int] = []
|
||||
self._on_sub_receive_funcs: list[int] = []
|
||||
self.name: str = _id
|
||||
self.is_main_receive_loop_running = False
|
||||
self.is_sub_receive_loop_running = False
|
||||
if type_check is None:
|
||||
type_check = self._get_generic_type() is not None
|
||||
elif type_check:
|
||||
if self._get_generic_type() is None:
|
||||
raise TypeError('Type hint is required for enforcing type check.')
|
||||
self.type_check = type_check
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `send(self, data: T) -> None`
|
||||
|
||||
 发送数据
|
||||
|
||||
Args:
|
||||
|
||||
data: 数据
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def send(self, data: T):
|
||||
"""
|
||||
发送数据
|
||||
Args:
|
||||
data: 数据
|
||||
"""
|
||||
if self.type_check:
|
||||
_type = self._get_generic_type()
|
||||
if _type is not None and (not self._validate_structure(data, _type)):
|
||||
raise TypeError(f'Data must be an instance of {_type}, {type(data)} found')
|
||||
if self._closed:
|
||||
raise RuntimeError('Cannot send to a closed channel_')
|
||||
self.conn_send.send(data)
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `receive(self) -> T`
|
||||
|
||||
 接收数据
|
||||
|
||||
Args:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def receive(self) -> T:
|
||||
"""
|
||||
接收数据
|
||||
Args:
|
||||
"""
|
||||
if self._closed:
|
||||
raise RuntimeError('Cannot receive from a closed channel_')
|
||||
while True:
|
||||
data = self.conn_recv.recv()
|
||||
return data
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `close(self) -> None`
|
||||
|
||||
 关闭通道
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def close(self):
|
||||
"""
|
||||
关闭通道
|
||||
"""
|
||||
self._closed = True
|
||||
self.conn_send.close()
|
||||
self.conn_recv.close()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_receive(self, filter_func: Optional[FILTER_FUNC]) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]`
|
||||
|
||||
 接收数据并执行函数
|
||||
|
||||
Args:
|
||||
|
||||
filter_func: 过滤函数,为None则不过滤
|
||||
|
||||
Returns:
|
||||
|
||||
装饰器,装饰一个函数在接收到数据后执行
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_receive(self, filter_func: Optional[FILTER_FUNC]=None) -> Callable[[Callable[[T], Any]], Callable[[T], Any]]:
|
||||
"""
|
||||
接收数据并执行函数
|
||||
Args:
|
||||
filter_func: 过滤函数,为None则不过滤
|
||||
Returns:
|
||||
装饰器,装饰一个函数在接收到数据后执行
|
||||
"""
|
||||
if not self.is_sub_receive_loop_running and (not IS_MAIN_PROCESS):
|
||||
threading.Thread(target=self._start_sub_receive_loop, daemon=True).start()
|
||||
if not self.is_main_receive_loop_running and IS_MAIN_PROCESS:
|
||||
threading.Thread(target=self._start_main_receive_loop, daemon=True).start()
|
||||
|
||||
def decorator(func: Callable[[T], Any]) -> Callable[[T], Any]:
|
||||
global _func_id
|
||||
|
||||
async def wrapper(data: T) -> Any:
|
||||
if filter_func is not None:
|
||||
if is_coroutine_callable(filter_func):
|
||||
if not await filter_func(data):
|
||||
return
|
||||
elif not filter_func(data):
|
||||
return
|
||||
if is_coroutine_callable(func):
|
||||
return await func(data)
|
||||
else:
|
||||
return func(data)
|
||||
_callback_funcs[_func_id] = wrapper
|
||||
if IS_MAIN_PROCESS:
|
||||
self._on_main_receive_funcs.append(_func_id)
|
||||
else:
|
||||
self._on_sub_receive_funcs.append(_func_id)
|
||||
_func_id += 1
|
||||
return func
|
||||
return decorator
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***var*** `T = TypeVar('T')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `channel_deliver_active_channel = Channel(_id='channel_deliver_active_channel')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `channel_deliver_passive_channel = Channel(_id='channel_deliver_passive_channel')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = data[1]['recv_chan']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = Channel[Channel[Any]]('recv_chan')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = Channel[dict[str, Channel[Any]]]('recv_chan')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `type_check = self._get_generic_type() is not None`
|
||||
|
||||
|
||||
|
||||
### ***var*** `data = self.conn_recv.recv()`
|
||||
|
||||
|
||||
|
||||
### ***var*** `func = _callback_funcs[func_id]`
|
||||
|
||||
|
||||
|
||||
### ***var*** `func = _callback_funcs[func_id]`
|
||||
|
||||
|
||||
|
||||
### ***var*** `data = self.conn_recv.recv()`
|
||||
|
||||
|
||||
|
||||
### ***var*** `data = self.conn_recv.recv()`
|
||||
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
title: liteyuki.comm.event
|
||||
order: 1
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***class*** `Event`
|
||||
|
||||
事件类
|
||||
|
||||
###   ***def*** `__init__(self, name: str, data: dict[str, Any]) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self, name: str, data: dict[str, Any]):
|
||||
self.name = name
|
||||
self.data = data
|
||||
```
|
||||
</details>
|
||||
|
@ -1,563 +0,0 @@
|
||||
---
|
||||
title: liteyuki.comm.storage
|
||||
order: 1
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***def*** `run_subscriber_receive_funcs(channel_: str, data: Any) -> None`
|
||||
|
||||
运行订阅者接收函数
|
||||
|
||||
Args:
|
||||
|
||||
channel_: 频道
|
||||
|
||||
data: 数据
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
def run_subscriber_receive_funcs(channel_: str, data: Any):
|
||||
"""
|
||||
运行订阅者接收函数
|
||||
Args:
|
||||
channel_: 频道
|
||||
data: 数据
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]:
|
||||
run_coroutine(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]])
|
||||
elif channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]:
|
||||
run_coroutine(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]])
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_get(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'get')
|
||||
def on_get(data: tuple[str, dict[str, Any]]):
|
||||
key = data[1]['key']
|
||||
default = data[1]['default']
|
||||
recv_chan = data[1]['recv_chan']
|
||||
recv_chan.send(shared_memory.get(key, default))
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_set(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'set')
|
||||
def on_set(data: tuple[str, dict[str, Any]]):
|
||||
key = data[1]['key']
|
||||
value = data[1]['value']
|
||||
shared_memory.set(key, value)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_delete(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'delete')
|
||||
def on_delete(data: tuple[str, dict[str, Any]]):
|
||||
key = data[1]['key']
|
||||
shared_memory.delete(key)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_get_all(data: tuple[str, dict[str, Any]]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@shared_memory.passive_chan.on_receive(lambda d: d[0] == 'get_all')
|
||||
def on_get_all(data: tuple[str, dict[str, Any]]):
|
||||
recv_chan = data[1]['recv_chan']
|
||||
recv_chan.send(shared_memory.get_all())
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `on_publish(data: tuple[str, Any]) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@channel.publish_channel.on_receive()
|
||||
def on_publish(data: tuple[str, Any]):
|
||||
channel_, data = data
|
||||
shared_memory.run_subscriber_receive_funcs(channel_, data)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC:
|
||||
|
||||
async def wrapper(data: Any):
|
||||
if is_coroutine_callable(func):
|
||||
await func(data)
|
||||
else:
|
||||
func(data)
|
||||
if IS_MAIN_PROCESS:
|
||||
if channel_ not in _on_main_subscriber_receive_funcs:
|
||||
_on_main_subscriber_receive_funcs[channel_] = []
|
||||
_on_main_subscriber_receive_funcs[channel_].append(wrapper)
|
||||
else:
|
||||
if channel_ not in _on_sub_subscriber_receive_funcs:
|
||||
_on_sub_subscriber_receive_funcs[channel_] = []
|
||||
_on_sub_subscriber_receive_funcs[channel_].append(wrapper)
|
||||
return wrapper
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***async def*** `wrapper(data: Any) -> None`
|
||||
|
||||
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
async def wrapper(data: Any):
|
||||
if is_coroutine_callable(func):
|
||||
await func(data)
|
||||
else:
|
||||
func(data)
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `Subscriber`
|
||||
|
||||
|
||||
|
||||
###   ***def*** `__init__(self) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self):
|
||||
self._subscribers = {}
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `receive(self) -> Any`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def receive(self) -> Any:
|
||||
pass
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `unsubscribe(self) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def unsubscribe(self) -> None:
|
||||
pass
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `KeyValueStore`
|
||||
|
||||
|
||||
|
||||
###   ***def*** `__init__(self) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def __init__(self):
|
||||
self._store = {}
|
||||
self.active_chan = Channel[tuple[str, Optional[dict[str, Any]]]](_id='shared_memory-active')
|
||||
self.passive_chan = Channel[tuple[str, Optional[dict[str, Any]]]](_id='shared_memory-passive')
|
||||
self.publish_channel = Channel[tuple[str, Any]](_id='shared_memory-publish')
|
||||
self.is_main_receive_loop_running = False
|
||||
self.is_sub_receive_loop_running = False
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `set(self, key: str, value: Any) -> None`
|
||||
|
||||
 设置键值对
|
||||
|
||||
Args:
|
||||
|
||||
key: 键
|
||||
|
||||
value: 值
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def set(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
设置键值对
|
||||
Args:
|
||||
key: 键
|
||||
value: 值
|
||||
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
lock = _get_lock(key)
|
||||
with lock:
|
||||
self._store[key] = value
|
||||
else:
|
||||
self.passive_chan.send(('set', {'key': key, 'value': value}))
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `get(self, key: str, default: Optional[Any]) -> Optional[Any]`
|
||||
|
||||
 获取键值对
|
||||
|
||||
Args:
|
||||
|
||||
key: 键
|
||||
|
||||
default: 默认值
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
Any: 值
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get(self, key: str, default: Optional[Any]=None) -> Optional[Any]:
|
||||
"""
|
||||
获取键值对
|
||||
Args:
|
||||
key: 键
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
Any: 值
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
lock = _get_lock(key)
|
||||
with lock:
|
||||
return self._store.get(key, default)
|
||||
else:
|
||||
recv_chan = Channel[Optional[Any]]('recv_chan')
|
||||
self.passive_chan.send(('get', {'key': key, 'default': default, 'recv_chan': recv_chan}))
|
||||
return recv_chan.receive()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `delete(self, key: str, ignore_key_error: bool) -> None`
|
||||
|
||||
 删除键值对
|
||||
|
||||
Args:
|
||||
|
||||
key: 键
|
||||
|
||||
ignore_key_error: 是否忽略键不存在的错误
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def delete(self, key: str, ignore_key_error: bool=True) -> None:
|
||||
"""
|
||||
删除键值对
|
||||
Args:
|
||||
key: 键
|
||||
ignore_key_error: 是否忽略键不存在的错误
|
||||
|
||||
Returns:
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
lock = _get_lock(key)
|
||||
with lock:
|
||||
if key in self._store:
|
||||
try:
|
||||
del self._store[key]
|
||||
del _locks[key]
|
||||
except KeyError as e:
|
||||
if not ignore_key_error:
|
||||
raise e
|
||||
else:
|
||||
self.passive_chan.send(('delete', {'key': key}))
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `get_all(self) -> dict[str, Any]`
|
||||
|
||||
 获取所有键值对
|
||||
|
||||
Returns:
|
||||
|
||||
dict[str, Any]: 键值对
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def get_all(self) -> dict[str, Any]:
|
||||
"""
|
||||
获取所有键值对
|
||||
Returns:
|
||||
dict[str, Any]: 键值对
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
return self._store
|
||||
else:
|
||||
recv_chan = Channel[dict[str, Any]]('recv_chan')
|
||||
self.passive_chan.send(('get_all', {'recv_chan': recv_chan}))
|
||||
return recv_chan.receive()
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `publish(self, channel_: str, data: Any) -> None`
|
||||
|
||||
 发布消息
|
||||
|
||||
Args:
|
||||
|
||||
channel_: 频道
|
||||
|
||||
data: 数据
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def publish(self, channel_: str, data: Any) -> None:
|
||||
"""
|
||||
发布消息
|
||||
Args:
|
||||
channel_: 频道
|
||||
data: 数据
|
||||
|
||||
Returns:
|
||||
"""
|
||||
self.active_chan.send(('publish', {'channel': channel_, 'data': data}))
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***def*** `on_subscriber_receive(self, channel_: str) -> Callable[[ON_RECEIVE_FUNC], ON_RECEIVE_FUNC]`
|
||||
|
||||
 订阅者接收消息时的回调
|
||||
|
||||
Args:
|
||||
|
||||
channel_: 频道
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
装饰器
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def on_subscriber_receive(self, channel_: str) -> Callable[[ON_RECEIVE_FUNC], ON_RECEIVE_FUNC]:
|
||||
"""
|
||||
订阅者接收消息时的回调
|
||||
Args:
|
||||
channel_: 频道
|
||||
|
||||
Returns:
|
||||
装饰器
|
||||
"""
|
||||
if IS_MAIN_PROCESS and (not self.is_main_receive_loop_running):
|
||||
threading.Thread(target=self._start_receive_loop, daemon=True).start()
|
||||
shared_memory.is_main_receive_loop_running = True
|
||||
elif not IS_MAIN_PROCESS and (not self.is_sub_receive_loop_running):
|
||||
threading.Thread(target=self._start_receive_loop, daemon=True).start()
|
||||
shared_memory.is_sub_receive_loop_running = True
|
||||
|
||||
def decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC:
|
||||
|
||||
async def wrapper(data: Any):
|
||||
if is_coroutine_callable(func):
|
||||
await func(data)
|
||||
else:
|
||||
func(data)
|
||||
if IS_MAIN_PROCESS:
|
||||
if channel_ not in _on_main_subscriber_receive_funcs:
|
||||
_on_main_subscriber_receive_funcs[channel_] = []
|
||||
_on_main_subscriber_receive_funcs[channel_].append(wrapper)
|
||||
else:
|
||||
if channel_ not in _on_sub_subscriber_receive_funcs:
|
||||
_on_sub_subscriber_receive_funcs[channel_] = []
|
||||
_on_sub_subscriber_receive_funcs[channel_].append(wrapper)
|
||||
return wrapper
|
||||
return decorator
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***@staticmethod***
|
||||
###   ***def*** `run_subscriber_receive_funcs(channel_: str, data: Any) -> None`
|
||||
|
||||
 运行订阅者接收函数
|
||||
|
||||
Args:
|
||||
|
||||
channel_: 频道
|
||||
|
||||
data: 数据
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
def run_subscriber_receive_funcs(channel_: str, data: Any):
|
||||
"""
|
||||
运行订阅者接收函数
|
||||
Args:
|
||||
channel_: 频道
|
||||
data: 数据
|
||||
"""
|
||||
if IS_MAIN_PROCESS:
|
||||
if channel_ in _on_main_subscriber_receive_funcs and _on_main_subscriber_receive_funcs[channel_]:
|
||||
run_coroutine(*[func(data) for func in _on_main_subscriber_receive_funcs[channel_]])
|
||||
elif channel_ in _on_sub_subscriber_receive_funcs and _on_sub_subscriber_receive_funcs[channel_]:
|
||||
run_coroutine(*[func(data) for func in _on_sub_subscriber_receive_funcs[channel_]])
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `GlobalKeyValueStore`
|
||||
|
||||
|
||||
|
||||
###   ***@classmethod***
|
||||
###   ***def*** `get_instance(cls: Any) -> None`
|
||||
|
||||
 
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
if cls._instance is None:
|
||||
with cls._lock:
|
||||
if cls._instance is None:
|
||||
cls._instance = KeyValueStore()
|
||||
return cls._instance
|
||||
```
|
||||
</details>
|
||||
|
||||
###   ***attr*** `_instance: None`
|
||||
|
||||
###   ***attr*** `_lock: threading.Lock()`
|
||||
|
||||
### ***var*** `key = data[1]['key']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `default = data[1]['default']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = data[1]['recv_chan']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `key = data[1]['key']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `value = data[1]['value']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `key = data[1]['key']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = data[1]['recv_chan']`
|
||||
|
||||
|
||||
|
||||
### ***var*** `lock = _get_lock(key)`
|
||||
|
||||
|
||||
|
||||
### ***var*** `lock = _get_lock(key)`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = Channel[Optional[Any]]('recv_chan')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `lock = _get_lock(key)`
|
||||
|
||||
|
||||
|
||||
### ***var*** `recv_chan = Channel[dict[str, Any]]('recv_chan')`
|
||||
|
||||
|
||||
|
||||
### ***var*** `data = self.active_chan.receive()`
|
||||
|
||||
|
||||
|
||||
### ***var*** `data = self.publish_channel.receive()`
|
||||
|
||||
|
||||
|
@ -1,231 +0,0 @@
|
||||
---
|
||||
title: liteyuki.config
|
||||
order: 1
|
||||
icon: laptop-code
|
||||
category: API
|
||||
---
|
||||
|
||||
### ***def*** `flat_config(config: dict[str, Any]) -> dict[str, Any]`
|
||||
|
||||
扁平化配置文件
|
||||
|
||||
|
||||
|
||||
{a:{b:{c:1}}} -> {"a.b.c": 1}
|
||||
|
||||
Args:
|
||||
|
||||
config: 配置项目
|
||||
|
||||
|
||||
|
||||
Returns:
|
||||
|
||||
扁平化后的配置文件,但也包含原有的键值对
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def flat_config(config: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
扁平化配置文件
|
||||
|
||||
{a:{b:{c:1}}} -> {"a.b.c": 1}
|
||||
Args:
|
||||
config: 配置项目
|
||||
|
||||
Returns:
|
||||
扁平化后的配置文件,但也包含原有的键值对
|
||||
"""
|
||||
new_config = copy.deepcopy(config)
|
||||
for key, value in config.items():
|
||||
if isinstance(value, dict):
|
||||
for k, v in flat_config(value).items():
|
||||
new_config[f'{key}.{k}'] = v
|
||||
return new_config
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_from_yaml(file: str) -> dict[str, Any]`
|
||||
|
||||
Load config from yaml file
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_from_yaml(file: str) -> dict[str, Any]:
|
||||
"""
|
||||
Load config from yaml file
|
||||
|
||||
"""
|
||||
logger.debug(f'Loading YAML config from {file}')
|
||||
config = yaml.safe_load(open(file, 'r', encoding='utf-8'))
|
||||
return flat_config(config if config is not None else {})
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_from_json(file: str) -> dict[str, Any]`
|
||||
|
||||
Load config from json file
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_from_json(file: str) -> dict[str, Any]:
|
||||
"""
|
||||
Load config from json file
|
||||
"""
|
||||
logger.debug(f'Loading JSON config from {file}')
|
||||
config = json.load(open(file, 'r', encoding='utf-8'))
|
||||
return flat_config(config if config is not None else {})
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_from_toml(file: str) -> dict[str, Any]`
|
||||
|
||||
Load config from toml file
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_from_toml(file: str) -> dict[str, Any]:
|
||||
"""
|
||||
Load config from toml file
|
||||
"""
|
||||
logger.debug(f'Loading TOML config from {file}')
|
||||
config = toml.load(open(file, 'r', encoding='utf-8'))
|
||||
return flat_config(config if config is not None else {})
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_from_files() -> dict[str, Any]`
|
||||
|
||||
从指定文件加载配置项,会自动识别文件格式
|
||||
|
||||
默认执行扁平化选项
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_from_files(*files: str, no_warning: bool=False) -> dict[str, Any]:
|
||||
"""
|
||||
从指定文件加载配置项,会自动识别文件格式
|
||||
默认执行扁平化选项
|
||||
"""
|
||||
config = {}
|
||||
for file in files:
|
||||
if os.path.exists(file):
|
||||
if file.endswith(('.yaml', 'yml')):
|
||||
config.update(load_from_yaml(file))
|
||||
elif file.endswith('.json'):
|
||||
config.update(load_from_json(file))
|
||||
elif file.endswith('.toml'):
|
||||
config.update(load_from_toml(file))
|
||||
elif not no_warning:
|
||||
logger.warning(f'Unsupported config file format: {file}')
|
||||
elif not no_warning:
|
||||
logger.warning(f'Config file not found: {file}')
|
||||
return config
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_configs_from_dirs() -> dict[str, Any]`
|
||||
|
||||
从目录下加载配置文件,不递归
|
||||
|
||||
按照读取文件的优先级反向覆盖
|
||||
|
||||
默认执行扁平化选项
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_configs_from_dirs(*directories: str, no_waring: bool=False) -> dict[str, Any]:
|
||||
"""
|
||||
从目录下加载配置文件,不递归
|
||||
按照读取文件的优先级反向覆盖
|
||||
默认执行扁平化选项
|
||||
"""
|
||||
config = {}
|
||||
for directory in directories:
|
||||
if not os.path.exists(directory):
|
||||
if not no_waring:
|
||||
logger.warning(f'Directory not found: {directory}')
|
||||
continue
|
||||
for file in os.listdir(directory):
|
||||
if file.endswith(_SUPPORTED_CONFIG_FORMATS):
|
||||
config.update(load_from_files(os.path.join(directory, file), no_warning=no_waring))
|
||||
return config
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***def*** `load_config_in_default(no_waring: bool) -> dict[str, Any]`
|
||||
|
||||
从一个标准的轻雪项目加载配置文件
|
||||
|
||||
项目目录下的config.*和config目录下的所有配置文件
|
||||
|
||||
项目目录下的配置文件优先
|
||||
|
||||
<details>
|
||||
<summary>源代码</summary>
|
||||
|
||||
```python
|
||||
def load_config_in_default(no_waring: bool=False) -> dict[str, Any]:
|
||||
"""
|
||||
从一个标准的轻雪项目加载配置文件
|
||||
项目目录下的config.*和config目录下的所有配置文件
|
||||
项目目录下的配置文件优先
|
||||
"""
|
||||
config = load_configs_from_dirs('config', no_waring=no_waring)
|
||||
config.update(load_from_files('config.yaml', 'config.toml', 'config.json', 'config.yml', no_warning=no_waring))
|
||||
return config
|
||||
```
|
||||
</details>
|
||||
|
||||
### ***class*** `SatoriNodeConfig(BaseModel)`
|
||||
|
||||
|
||||
|
||||
### ***class*** `SatoriConfig(BaseModel)`
|
||||
|
||||
|
||||
|
||||
### ***class*** `BasicConfig(BaseModel)`
|
||||
|
||||
|
||||
|
||||
### ***var*** `new_config = copy.deepcopy(config)`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = yaml.safe_load(open(file, 'r', encoding='utf-8'))`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = json.load(open(file, 'r', encoding='utf-8'))`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = toml.load(open(file, 'r', encoding='utf-8'))`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = {}`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = {}`
|
||||
|
||||
|
||||
|
||||
### ***var*** `config = load_configs_from_dirs('config', no_waring=no_waring)`
|
||||
|
||||
|
||||
|