Ⓜ️手动从旧梦 81a191f merge

This commit is contained in:
EillesWan 2024-08-12 11:44:30 +08:00
parent 068feaa591
commit 2d67a703bd
214 changed files with 6457 additions and 10418 deletions

1
.gitignore vendored
View File

@ -29,6 +29,7 @@ src/plugins/trimo_plugin_msctconverter/MusicPreview/assets/wav
test.py test.py
line_count.py line_count.py
mypy.ini
# nuitka # nuitka
main.build/ main.build/

5
docs/.gitignore vendored
View File

@ -1,5 +0,0 @@
node_modules/
./.vuepress/.cache/
./.vuepress/.temp/
./.vuepress/dist/

View File

@ -1,13 +0,0 @@
import {defineClientConfig} from "vuepress/client";
import resourceStoreComp from "./components/ResStore.vue";
import pluginStoreComp from "./components/PluginStore.vue";
//导入element-plus
import ElementPlus from 'element-plus';
export default defineClientConfig({
enhance: ({app, router, siteData}) => {
app.component("resourceStoreComp", resourceStoreComp);
app.component("pluginStoreComp", pluginStoreComp);
app.use(ElementPlus);
},
});

View File

@ -1,126 +0,0 @@
<template>
<div class="item-card">
<div class="item-name">{{ props.item.name }}</div>
<div class="item-description">{{ props.item.desc }}</div>
<div class="item-bar">
<!-- 三个可点击svg一个github一个下载一个可点击"https://github.com/{{ username }}.png?size=80"个人头像配上id-->
<a :href=props.item.homepage class="btn">
<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="btn copy-btn" @click="copyToClipboard">复制安装命令</button>
<div class="btn">
<a class="author-info" :href="`https://github.com/${props.item.author }`">
<img class="icon avatar" :src="`https://github.com/${ props.item.author }.png?size=80`" alt="">
<div class="author-name">{{ props.item.author }}</div>
</a>
</div>
<!-- 复制键复制安装命令npm install props.item.module_name-->
</div>
</div>
</template>
<script setup lang="ts">
import {defineProps, onMounted} from 'vue'
import Clipboard from 'clipboard'
//
//
const props = defineProps({
item: Object
})
const copyToClipboard = () => {
const clipboard = new Clipboard('.copy-btn', {
text: () => `npm install ${props.item.module_name}`
})
clipboard.on('success', () => {
})
clipboard.on('error', () => {
})
}
//
</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;
}
button {
background-color: #00000000;
border: none;
}
.copy-btn {
cursor: pointer;
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;
bottom: 0;
height: 50px;
display: flex;
align-items: center;
box-sizing: border-box;
justify-content: space-between;
color: #00000055;
}
</style>

View File

@ -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>

View File

@ -1,90 +0,0 @@
<template>
<div class="item-card">
<div class="item-name">{{ props.item.name }}</div>
<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="">
<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>
<div><a class="author-info" :href="`https://github.com/${props.item.author }`">
<img class="icon avatar" :src="`https://github.com/${ props.item.author }.png?size=80`" alt="">
<div class="author-name">{{ props.item.author }}</div>
</a>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {defineProps} from 'vue'
const props = defineProps({
item: Object
})
</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;
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;
bottom: 0;
height: 50px;
display: flex;
align-items: center;
box-sizing: border-box;
justify-content: space-between;
color: #00000055;
}
</style>

View File

@ -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>

View File

@ -1,30 +0,0 @@
import {defineUserConfig} from "vuepress";
import theme from "./theme.js";
import viteBundler from "@vuepress/bundler-vite";
export default defineUserConfig({
base: "/",
lang: "zh-CN",
title: "LiteyukiBot 轻雪机器人",
description: "LiteyukiBot | 轻雪机器人 | An OneBot Standard ChatBot | 一个OneBot标准的聊天机器人",
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,
});

View File

@ -1,20 +0,0 @@
import {navbar} from "vuepress-theme-hope";
export default navbar([
"/",
{
text: "项目部署",
link: "/deployment/",
prefix: "deployment/",
},
{
text: "使用手册",
link: "/usage/",
prefix: "usage/",
},
{
text: "商店",
link: "/store/resource",
prefix: "store/",
}
]);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -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

View File

@ -1,23 +0,0 @@
[
{
"module_name": "nonebot_plugin_status",
"project_link": "nonebot-plugin-status",
"name": "测试",
"desc": "测试",
"author": "snowykami",
"homepage": "https://github.com/nonebot/plugin-status",
"tags": [
{
"label": "server",
"color": "#aeeaa8"
}
],
"is_official": true,
"type": "application",
"supported_adapters": null,
"valid": true,
"version": "0.8.1",
"time": "2024-03-04T06:57:10.250823Z",
"skip_test": false
}
]

View File

@ -1,56 +0,0 @@
[
{
"name": "KawaiiStatus",
"author": "SnowyKami",
"description": "可爱的状态卡片仿照koishi的制作",
"link": "https://cdn.liteyuki.icu/static/lrp/KawaiiStatus.zip"
},
{
"name": "MiSans字体包",
"author": "SnowyKami",
"description": "小米官方字体MiSans",
"link": "https://cdn.liteyuki.icu/static/lrp/MiSansFonts.zip"
},
{
"name": "MapleMono字体包",
"author": "SnowyKami",
"description": "适用于字母的字体包",
"link": "https://cdn.liteyuki.icu/static/lrp/MapleMonoFonts.zip"
},
{
"name": "野兽先辈主题HomoTheme",
"author": "SnowyKami",
"description": "野兽先辈主题包114514",
"link": "https://cdn.liteyuki.icu/static/lrp/HomoTheme.zip"
},
{
"name": "自定义设备信息",
"author": "SnowyKami",
"description": "自定义服务端的设备信息,自行修改使用",
"link": "https://cdn.liteyuki.icu/static/lrp/custom-device.zip"
},
{
"name": "轻雪傲娇系词库",
"author": "SnowyKami",
"description": "使用https://github.com/Kyomotoi/AnimeThesaurus的词库",
"link": "https://cdn.liteyuki.icu/static/lrp/liteyuki_words_aojiao.zip"
},
{
"name": "轻雪可爱系词库",
"author": "SnowyKami",
"description": "使用https://github.com/Kyomotoi/AnimeThesaurus的词库",
"link": "https://cdn.liteyuki.icu/static/lrp/liteyuki_words_kawaii.zip"
},
{
"name": "轻雪Kakyo语言包",
"author": "Nanaloveyuki",
"description": "Liteyuki Bot的语言包用于提供多种语言的翻译。",
"link": "https://github.com/Nanaloveyuki/liteyuki-langpack/releases/download/KakyoVer/Kakyo-pack.zip"
},
{
"name": "更多背景模板包",
"author": "snowykami",
"description": "自定义各种卡片的背景",
"link": "https://cdn.liteyuki.icu/static/lrp/morebg.zip"
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

View File

@ -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

View File

@ -1,22 +0,0 @@
function applyStyle() {
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' style='display: flex; background-color: #32383D'>" +
" <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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

View File

@ -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

View File

@ -1,25 +0,0 @@
import {sidebar} from "vuepress-theme-hope";
export default sidebar({
"/": [
"",
{
text: "项目部署",
icon: "laptop-code",
prefix: "deployment/",
children: "structure",
},
{
text: "使用手册",
icon: "book",
prefix: "usage/",
children: "structure",
},
{
text: "商店",
icon: "store",
prefix: "store/",
children: "structure",
}
],
});

View File

@ -1,7 +0,0 @@
// you can change config here
$colors: #c0392b, #d35400, #f39c12, #27ae60, #16a085, #2980b9, #8e44ad, #2c3e50,
#7f8c8d !default;
body {
overflow-x: hidden;
}

View File

@ -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%;
}

View File

@ -1,2 +0,0 @@
// you can change colors here
$theme-color: #00a6ff;

View File

@ -1,192 +0,0 @@
import {hopeTheme} from "vuepress-theme-hope";
import navbar from "./navbar.js";
import sidebar from "./sidebar.js";
export default hopeTheme({
hostname: "https://vuepress-theme-hope-docs-demo.netlify.app",
author: {
name: "远野千束",
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",
// 导航栏
navbar,
// 侧边栏
sidebar,
// 页脚
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: {
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",
// },
// ],
// },
// ],
// },
// },
},
});

View File

@ -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 轻雪机器人基于NoneBot2构建的综合应用型聊天机器人
actions:
- text: 快速部署
icon: rocket
link: ./deployment/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: 基于NoneBot2
icon: robot
details: 拥有良好的生态支持
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/snowykami/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
---

View File

@ -1,86 +0,0 @@
---
home: true
icon: home
title: 首页
heroImage: https://cdn.liteyuki.icu/static/img/logo.png
bgImage:
bgImageDark:
bgImageStyle:
background-attachment: fixed
heroText: LiteyukiBot
tagline: 轻雪机器人一个以轻量和简洁为设计理念基于Nonebot2的OneBot标准聊天机器人
actions:
- text: 快速部署
icon: lightbulb
link: ./deployment/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: 基于Nonebot2
icon: robot
details: 拥有良好的生态支持
link: https://nonebot.dev/
- title: 便捷插件管理
icon: plug
details: 使用<code>包管理器</code>,无需命令行操作即可安装/卸载插件
- title: 人性化交互
icon: mouse-pointer
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个插件3s内启动
- title: 滚动更新
icon: cloud-download
details: 让你的机器人保持最新提交
- title: 开源
icon: code
details: 项目遵循MIT协议开源欢迎各位的贡献
- 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/snowykami/LiteyukiBot</code> 以克隆项目至本地。
details: 如果无法连接到GitHub可以使用 <code>git clone https://gitee.com/snowykami/LiteyukiBot</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
---

View File

@ -1,8 +0,0 @@
---
title: 项目部署
index: false
icon: laptop-code
category: 部署
---
<Catalog />

View File

@ -1,62 +0,0 @@
---
title: 配置
icon: cog
order: 2
category: 使用指南
tag:
- 配置
- 部署
---
首次运行后生成`config.yml`,你可以修改配置项后重启轻雪,绝大多数情况下,你只需要修改`superusers`和`nickname`字段即可
## **基础配置项**
```yaml
command_start: [ "/", "" ] # 指令前缀,若没有""空命令头请开启alconna_use_command_start保证alconna解析正常
host: 127.0.0.1 # 监听地址默认为本机若要接收外部请求请填写0.0.0.0
port: 20216 # 绑定端口
nickname: [ "liteyuki" ] # 机器人昵称列表
superusers: [ "1919810" ] # 超级用户列表
```
## **其他配置**
以下为默认值,如需自定义请手动添加
```yaml
onebot_access_token: "" # 访问令牌,对公开放时建议设置
default_language: "zh-CN" # 默认语言
alconna_auto_completion: false # alconna是否自动补全指令默认false建议开启
# 开发者选项
allow_update: true # 是否允许更新
log_level: "INFO" # 日志等级
log_icon: true # 是否显示日志等级图标(某些控制台字体不可用)
auto_report: true # 是否自动上报问题给轻雪服务器
auto_update: true # 是否自动更新轻雪每天4点检查更新
debug: false # 轻雪调试开启会自动重载Bot或者资源其他插件自带的调试功能也将开启
safe_mode: false # 安全模式,开启后将不会加载任何第三方插件
# 其他Nonebot插件的配置项
custom_config_1: "custom_value1"
custom_config_2: "custom_value2"
...
```
> [!tip]
> 如果要使用dotenv配置文件请自行创建`.env.{ENVIRONMENT}`,并在`config.yml`中添加`environment:{ENVIRONMENT}`字段
## **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支持的任何适配器

View File

@ -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)提供的字体,且遵守了相关字体开源协议

View File

@ -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/snowykami/LiteyukiBot --depth=1
# 切换到Bot目录下
cd LiteyukiBot
# 安装依赖
pip install -r requirements.txt
# 启动Bot
python main.py
```
> [!tip]
> 推荐使用虚拟环境来运行轻雪,以避免依赖冲突,你可以使用`python -m venv venv`来创建虚拟环境,然后使用`venv\Scripts\activate`来激活虚拟环境
### **使用Docker构建镜像部署**
1. 安装 [`Docker`](https://docs.docker.com/get-docker/)
2. 克隆项目 `git clone https://github.com/snowykami/LiteyukiBot`
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)

View File

@ -1,107 +0,0 @@
---
home: true
icon: home
title: 首页
heroImage: https://cdn.liteyuki.icu/static/img/lykwi.png
bgImage:
bgImageDark:
bgImageStyle:
background-attachment: fixed
heroText: HeavylavaBot666 # LiteyukiBot 6
tagline: 重浆机器人一个以笨重和复杂为设计理念基于Koishi114514的TwoBotv1919810标准聊天机器人可用于雪地清扫使用Typethon编写
#tagline: 轻雪机器人一个以轻量和简洁为设计理念基于Nonebot2的OneBot标准聊天机器人
# 泰普森(X
actions:
- text: 快速结束 # 快速开始
icon: lightbulb
link: ./deployment/install.html
type: primary
- text: 奇怪的册子 # 使用手册
icon: book
link: ./usage/basic_command.html
#1. 安装 `Git``Python3.10+` 环境
#2. 克隆项目 `git clone https://github.com/snowykami/LiteyukiBot` (无法连接可以用`https://gitee.com/snowykami/LiteyukiBot`)
#3. 切换目录`cd LiteyukiBot`
#4. 安装依赖`pip install -r requirements.txt`(如果多个Python环境请指定后安装`pythonx -m pip install -r requirements.txt`)
#5. 启动`python main.py`
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: 基于Koishi.js233
icon: robot
details: 拥有辣鸡的生态支持
link: https://nonebot.dev/
- title: 盲目插件管理
icon: plug
details: 基于nbshi使用<code>xmpn和bib</code>,让你无法安装/卸载插件
- title: 纯命令行
icon: mouse-pointer
details: 老的掉牙的交互模式,必须手打指令
- title: 猪蹄支持
icon: paint-brush
details: 支持多种烤猪蹄样式,丢弃烤箱,拥抱烧烤架,满足你的干饭需求
- title: 去国际化
icon: globe
details: 支持多种语言包括i18n部分语言和自行扩展的语言代码
link: https://baike.baidu.com/item/i18n/6771940
- title: 超难配置
icon: cog
details: 无需过多配置,开箱即用
link: https://bot.liteyuki.icu/deployment/config.html
- title: 高占用
icon: memory
details: 使用更多的意义不明的依赖和资源
- title: 一个Bot标准
icon: link
details: 支持OneBotv11/12标准的四种通信协议
link: https://onebot.dev/
- title: Alconna
icon: link
details: 使用Alconna实现低效命令解析
link: https://github.com/nonebot/plugin-alconna
- title: 不准更新
icon: cloud-download
details: 要更新自己写新版本去
- title: 服务支持
icon: server
details: 内置重浆API但随时可能提桶跑路
- title: 闭源
icon: code
details: 要源代码自己逆向去
- 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: 安装 winget 和 nothing.js # git & node.js+
- title: 使用 <code>git clone https://github.com/snowykami/LiteyukiBot</code> 以克隆项目至FTP。 # 本地
details: 如果无法连接到PoonHub可以使用 <code>git clone https://gitee.com/snowykami/LiteyukiBot</code>
- title: 使用 <code>cd LiteyukiBot</code> 切换到项目目录。
- title: 使用 <code>npm install -r requirements.txt</code> 安装项目依赖。
details: 如果你有多个 nothing.js 环境,请使用 <code>pythonx -m npm install -r requirements.txt</code>
- title: 使用 <code>node main.py</code> 启动项目。
copyright: © 2021-2024 SnowyKami All Rights Reserved
---

View File

@ -1,27 +0,0 @@
{
"name": "liteyuki",
"version": "2.0.0",
"description": "A project of vuepress-theme-hope",
"license": "MIT",
"type": "module",
"scripts": {
"docs:build": "vuepress-vite build .",
"docs:clean-dev": "vuepress-vite dev . --clean-cache",
"docs:dev": "vuepress-vite dev .",
"docs:update-package": "pnpm dlx vp-update"
},
"devDependencies": {
"@vuepress/bundler-vite": "2.0.0-rc.9",
"@vuepress/plugin-search": "2.0.0-rc.24",
"vue": "^3.4.21",
"vuepress": "2.0.0-rc.9",
"vuepress-plugin-search-pro": "2.0.0-rc.34",
"vuepress-theme-hope": "2.0.0-rc.32"
},
"dependencies": {
"clipboard": "^2.0.11",
"element-plus": "^2.7.0",
"element-ui": "^2.15.14",
"vue-router": "^4.4.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
---
title: 资源商店
icon: store
index: false
---

View File

@ -1,8 +0,0 @@
---
title: 插件商店
icon: plug
order: 2
category: 使用手册
---
<pluginStoreComp />

View File

@ -1,7 +0,0 @@
---
title: 资源商店
icon: box
order: 1
category: 使用手册
---
<resourceStoreComp />

View File

@ -1,15 +0,0 @@
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2022",
"allowSyntheticDefaultImports": true
},
"include": [
"./.vuepress/**/*.ts",
"./.vuepress/**/*.vue"
],
"exclude": [
"node_modules"
]
}

View File

@ -1,8 +0,0 @@
---
title: 使用手册
index: false
icon: laptop-code
category: 使用手册
---
<Catalog />

View File

@ -1,16 +0,0 @@
---
title: 用户协议
icon: user-secret
order: 3
category: 使用手册
---
1. 本项目遵循`MIT`协议,你可以自由使用,修改,分发,但是请保留原作者信息
2. 你可以选择开启`auto_report`(默认开启),轻雪会收集以下内容
- 运行环境的设备信息CPU内存系统信息Python信息
- 插件信息(不含插件数据)
- 部分异常信息,
- 会话负载信息(不含隐私部分)
以上内容仅用于项目的优化,不包含任何隐私信息,且通过安全的方式传输到轻雪的服务器,若你不希望提供这些信息,可以在配置文件中把`auto_report`设定为`false`
3. 本项目不会收集用户的任何隐私信息,但请注意甄别第三方插件的安全性
4. 使用此项目代表你已经同意以上协议

View File

@ -1,124 +0,0 @@
---
title: 基础命令
icon: comment
order: 1
category: 使用手册
---
# 基础插件
---
> [!tip]
> **参数**`<param>`为必填参数,`[option]`为可选参数。
>
> **命令别名**:配置了命令别名的命令可以使用别名代替原命令,例如`npm install ~`可以使用`插件 安装 ~`代替。
## **轻雪命令`liteyuki_command`**
| 命令 | 说明 | 权限 | 举例 | 可用参数 |
| :----------------------------------------: | :---------------------------------------------------------------------------------------------: | :----------------------------------------: | :---------------------------------------------------------: | :----------------------------------------------------------------------------------: |
| `reload-liteyuki` | 重载轻雪 | 超级用户 | ❌ | ❌ |
| `update-liteyuki` | 更新轻雪 | 超级用户 | ❌ | ❌ |
| `liteecho` | 查看当前bot 版本 | 超级用户 | ❌ | ❌ |
| `status` | 查看统计信息和状态 | 超级用户 | ❌ | ❌ |
| `config set <key> value` | 添加配置项,若存在则会覆盖,输入值会被执行以转换为正确的类型,"10"和10是不一样的 | 超级用户 | `config set name 'liteyuki-bot'` | `<key>`: 若存在则覆盖, 若不存在则创建于`config.yml` ; `value`: yml格式的所有合法内容 |
| `config get [key] ` | 查询配置项不带key返回配置项列表推荐私聊使用 | 超级用户 | `config get name` | `<key>`: 若存在则返回, 若不存在则返回空 |
| `switch-image-mode ` | 在普通图片和Markdown大图之间切换该功能需要commit:505468b及以后的Lagrange.OneBot默认普通图片 | 超级用户 | `switch-image-mode` | ❌ |
| `/api api_name [args] ` | 调用机器人API | 超级用户 | `/api get_group_member_list group_id=1234567` | `<args>`: 参数列表, 格式为onebot v11协议api, 可用%20代替空格 |
| `/function function_name [args] [kwargs] ` | 调用机器人函数(`.lyfunction`语法) | 超级用户 | `/function send_group_msg group_id=1234567 message='hello'` | `<args>`和`<kwargs>`: 参数列表, api格式为onebot v11协议api |
| group enable/disable [group_id] | 在群聊启用/停用机器人group_id仅超级用户可用 | 超级用户,群聊仅群主、管理员、超级用户可用 | `group enable 1145141919810` | `<group_id>`: 群号 |
| liteyuki-docs | 查看轻雪文档 | 所有人 | ❌ | ❌ |
---
### **命令别名**
| 命令 | 别名 |
| :---------------: | :----------------------------------: |
| status | 状态 |
| reload-liteyuki | 重启轻雪 |
| update-liteyuki | 更新轻雪 |
| reload-resources | 重载资源 |
| config | 配置, `set` 设置 / `get` 查询 |
| switch-image-mode | 切换图片模式 |
| liteyuki-docs | 轻雪文档 |
| group | 群聊, `enable` 启用 / `disable` 停用 |
---
## **插件/包管理器 `liteyuki_pacman`**
- 插件管理
| 命令 | 说明 | 权限 |
| :-----------------------------------------------------: | :----------------------------------------: | :----------------------------------------------: |
| `npm update` | 更新插件商店索引 | 超级用户 |
| `npm install <plugin_name>` | 安装插件 | 超级用户 |
| `npm uninstall <plugin_name>` | 卸载插件 | 超级用户 |
| `npm search <keywords...>` | 通过关键词搜索插件 | 超级用户 |
| `npm enable-global/disable-global <plugin_name>` | 全局启用/停用插件 | 超级用户 |
| `npm enable/disable <plugin_name> [--group <group_id>]` | 当前会话启用/停用插件 | 群聊仅群主、管理员、超级用户可用,私聊所有人可用 |
| `npm list [page] [num]` | 列出所有插件 page为页数num为每页显示数量 | 群聊仅群主、管理员、超级用户可用,私聊所有人可用 |
| `help <plugin_name>` | 查看插件帮助 | 所有人 |
- 资源包管理
| 命令 | 说明 | 权限 |
| :----------------------: | :------------------------------------------: | :------: |
| `rpm list [page] [num]` | 列出所有资源包 page为页数num为每页显示数量 | 超级用户 |
| `rpm load <pack_name>` | 加载资源包 | 超级用户 |
| `rpm unload <pack_name>` | 卸载资源包 | 超级用户 |
| `rpm change <pack_name>` | 修改优先级 | 超级用户 |
| `rpm reload` | 重载所有资源包 | 超级用户 |
### 命令别名
| 命令 | 别名 |
| :--------------: | :------: |
| `npm` | 插件管理 |
| `update` | 更新 |
| `install` | 安装 |
| `uninstall` | 卸载 |
| `search` | 搜索 |
| `enable` | 启用 |
| `disable` | 停用 |
| `enable-global` | 全局启用 |
| `disable-global` | 全局停用 |
| `rpm` | 资源包 |
| `load` | 加载 |
| `unload` | 卸载 |
| `change` | 更改 |
| `reload` | 重载 |
| `list` | 列表 |
| `help` | 帮助 |
> [!warning]
> 受限于NoneBot2钩子函数的依赖注入参数插件停用只能阻断传入响应对于主动推送的插件不生效请阅读插件主页的说明。
>
---
## **用户管理`liteyuki_user`**
| 命令 | 说明 | 权限 |
| :-------------------------: | :----------------------------: | :----: |
| `profile` | 查看用户信息菜单 | 所有人 |
| `profile set <key> [value]` | 设置用户信息或打开属性设置菜单 | 所有人 |
| `profile get <key>` | 获取用户信息 | 所有人 |
###命令别名
| 命令 | 别名 |
| :-------: | :------: |
| `profile` | 个人信息 |
| `set` | 设置 |
| `get` | 查询 |

View File

@ -1,70 +0,0 @@
---
title: 功能命令
icon: comment
order: 2
category: 使用手册
---
## 功能插件命令
### **轻雪天气`liteyuki_weather`**
查询实时天气,支持绑定城市,支持中英文城市名,支持多个关键词查询。
配置项
```yaml
weather_key: "" # 和风天气的天气key会自动判断key版本
```
命令
```shell
weather <keywords...> # Keywords为城市名支持中英文
```
查询目标地实时天气,例如:"天气 北京 海淀", "weather Tokyo Shinjuku"
```shell
bind-city <keywords...> # Keywords为城市名支持中英文
```
绑定查询城市,个人全局生效
#### 命令别名
| 命令 | 别名 |
| :-------: | :------- |
| weather | 天气 |
| bind-city | 绑定城市 |
---
### **统计信息`liteyuki_statistics`**
统计信息
命令
```shell
statistic message --duration <duration> --period <period> --group [current|group_id] --bot [current|bot_id]
```
功能: 用于统计Bot接收到的消息, 统计周期为`period`, 统计时间范围为`duration`
| 参数 | 格式 |
| :------: | :------------------------------------------------------------: |
| duration | 使用通用日期简写: `1d`(天), `1h`(小时), `45m`(分钟), `14s`(秒) |
| period | 使用通用日期简写: `1d`(天), `1h`(小时), `45m`(分钟), `14s`(秒) |
| group | `current` (当前群聊) 或 `group_id` (QQ群号) |
| bot | `current` (当前Bot) 或 `bot_id` |
#### 命令别名
| 命令 | 别名 |
| :----------: | :---: |
| `statistic` | stat |
| `message` | m |
| `--duration` | -d |
| --period` | -p |
| `--group` | -g |
| `--bot` | -b |
| `current` | c |

View File

@ -1,45 +0,0 @@
---
title: 轻雪API
icon: code
order: 5
category: 使用指南
tag:
- 配置
- 部署
---
## **轻雪API**
轻雪API是轻雪运行中部分服务的支持由`go`语言编写,例如错误反馈,图床链接等,目前服务由轻雪服务器提供,用户无需额外部署
接口
- `url` `https://api.liteyuki.icu`
- `POST` `/register` 注册一个Bot
- 参数
- `name` `string` Bot名称
- `version` `string` Bot版本
- `version_id` `int` Bot版本ID
- `python` `string` Python版本
- `os` `string` 操作系统
- 返回
- `code` `int` 状态码
- `liteyuki_id` `string` 轻雪ID
- `POST` `/bug_report` 上报错误
- 参数
- `liteyuki_id` `string` 轻雪ID
- `content` `string` 错误信息
- `device_info` `string` 设备信息
- 返回
- `code` `int` 状态码
- `report_id` `string` 错误ID
- `POST` `/upload_image` 图床上传
- 参数
- `image` `file` 图片文件
- `liteyuki_id` `string` 轻雪ID,用于鉴权
- 返回
- `code` `int` 状态码
- `url` `string` 图床链接

View File

@ -1,72 +0,0 @@
---
title: 轻雪函数
icon: code
order: 4
category: 使用指南
tag:
- 配置
---
## **轻雪函数**
轻雪函数 Liteyuki Function 是轻雪的一个功能它允许你在轻雪中运行一些自定义的由数据驱动的命令类似于Minecraft的mcfunction.
### **函数文件**
函数文件放在资源包的`functions`目录下,文件名以`.mcfunction` `.lyfunction` `.lyf`结尾,例如`test.mcfunction`,文件内容为一系列的命令,每行一个命令,支持单行注释`#`(编辑时的语法高亮可采取`shell`格式),例如:
```shell
# 在发信器输出"hello world"
cmd echo hello world
# 如果你想同时输出多行内容可以尝试换行符(Python格式)
cmd echo hello world\nLiteyuki bot
```
也支持句末注释,例如:
```shell
cmd echo hello world # 输出"hello world"
```
### **命令文档**
```shell
var <var1=value1> [var2=value2] ... # 定义变量
cmd <command> # 在设备上执行命令
api <api_name> [var=value...] # 调用Bot API
function <func_name> # 调用函数,可递归
sleep <time> # 异步等待单位s
nohup <command> # 使用新的task执行命令即不等待
end # 结束函数关键字包括子task
await # 等待所有异步任务结束若函数中启动了其他task需要在最后调用否则task对象会被销毁
```
#### **示例**
```shell
# 疯狂戳好友
# 使用 /function poke user_id=123456 执行
# 每隔0.2s戳两次,无限戳,会触发最大递归深度限制
# 若要戳20s后停止则需要删除await添加sleep 20和end
api friend_poke user_id=user_id
api friend_poke user_id=user_id
sleep 0.2
nohup function poke
await
```
### **API**
理论上所有基于onebotv11的api都可调用不同Adapter api也有差别.
[Onebot v11 API文档](https://283375.github.io/onebot_v11_vitepress/api/index.html)
### **结束关键字**
由于LiteyukiBot基于异步运行, 所以在编写lyfunction时也要注意异步的调用避免出现"单线程走到底"的情况是效率提升的关键.
`await` 异步任务结束关键字用于结束当前已完成function的执行
> [!warning]
> 但若出现非单function的情况有一个task任务没有完成而await被执行了那么当前所有函数包的task都会被截停销毁

View File

@ -1,42 +0,0 @@
---
title: 资源包
icon: paint-brush
order: 3
category: 使用手册
---
## 简介
资源包,亦可根据用途称为主题包、字体包、语言包等,它允许你一定程度上自定义轻雪的外观,并且不用修改源代码
- [资源/主题商店](/store/)提供了一些资源包供你选择,你也可以自己制作资源包
- 资源包的制作很简单,如果你接触过`Minecraft`的资源包,那么你能够很快就上手,仅需按照原有路径进行文件替换即可,讲起打包成一个新的资源包。
- 部分内容制作需要一点点前端基础,例如`html``css`
- 轻雪原版资源包请查看`LiteyukiBot/liteyuki/resources`,可以在此基础上进行修改
- 欢迎各位投稿资源包到轻雪资源商店
请注意主题包中的html渲染使用Js来规定数据的渲染位置请确保您所编写的html代码能被Bot解析否则会导致渲染失败或渲染结果不理想/异常/错位等无法预料的事情发生。推荐在编写html时同时更改对应Js代码以避免出现无法预料的问题。
---
## 加载资源包
- 资源包通常是以`.zip`格式压缩的,只需要将其解压到根目录`resources`目录下即可,注意不要嵌套文件夹,正常的路径应该是这样的
```shell
main.py
resources
└─resource_pack_1
├─metadata.yml
├─templates
└───...
└─resource_pack_2
├─metadata.yml
└─...
```
- 你自己制作的资源包也应该遵循这个规则,并且应该在`metadata.yml`中填写一些信息
- 若没有`metadata.yml`文件,则该文件夹不会被识别为资源包
```yaml
name: "资源包名称"
version: "1.0.0"
description: "资源包描述"
# 你可以自定义一些信息,但请保证以上三个字段
...
```
- 资源包加载遵循一个优先级即后加载的资源包会覆盖前面的资源包例如你在A包中定义了一个`index.html`文件B包也定义了一个`index.html`文件那么加载B包后A包中的`index.html`文件会被覆盖
- 对于不同资源包的不同文件是可以相对引用的例如你在A中定义了`templates/index.html`在B中定义了`templates/style.css`可以在A的`index.html`中用`./style.css`相对路径引用B中的css

View File

@ -3,10 +3,19 @@ from liteyuki.bot import (
get_bot get_bot
) )
# def get_bot_instance() -> LiteyukiBot | None: from liteyuki.comm import (
# """ Channel,
# 获取轻雪实例 chan,
# Returns: Event
# LiteyukiBot: 当前的轻雪实例 )
# """
# return _BOT_INSTANCE from liteyuki.plugin import (
load_plugin,
load_plugins
)
from liteyuki.log import (
logger,
init_log
)

View File

@ -1,147 +1,137 @@
import asyncio import asyncio
import multiprocessing import os
from typing import Any, Coroutine, Optional import platform
import sys
import threading
import time
from typing import Any, Optional
import nonebot from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from liteyuki.plugin.load import load_plugin, load_plugins from liteyuki.bot.lifespan import LIFESPAN_FUNC, Lifespan
from src.utils import ( from liteyuki.core import IS_MAIN_PROCESS
adapter_manager, from liteyuki.core.manager import ProcessManager
driver_manager, from liteyuki.core.spawn_process import mb_run, nb_run
) from liteyuki.log import init_log, logger
from src.utils.base.log import logger from liteyuki.plugin import load_plugins
from liteyuki.bot.lifespan import (
Lifespan,
LIFESPAN_FUNC,
)
from liteyuki.core.spawn_process import nb_run, ProcessingManager
__all__ = [ __all__ = ["LiteyukiBot", "get_bot"]
"LiteyukiBot",
"get_bot"
]
_MAIN_PROCESS = multiprocessing.current_process().name == "MainProcess"
class LiteyukiBot: class LiteyukiBot:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
global _BOT_INSTANCE global _BOT_INSTANCE
_BOT_INSTANCE = self # 引用 _BOT_INSTANCE = self # 引用
self.running = False
self.config: dict[str, Any] = kwargs self.config: dict[str, Any] = kwargs
self.lifespan: Lifespan = Lifespan()
self.init(**self.config) # 初始化 self.init(**self.config) # 初始化
def run(self, *args, **kwargs): self.lifespan: Lifespan = Lifespan()
if _MAIN_PROCESS: self.process_manager: ProcessManager = ProcessManager(bot=self)
load_plugins("liteyuki/plugins") self.loop = asyncio.new_event_loop()
asyncio.run(self.lifespan.before_start()) asyncio.set_event_loop(self.loop)
self._run_nb_in_spawn_process(*args, **kwargs) self.loop_thread = threading.Thread(target=self.loop.run_forever, daemon=True)
else: self.call_restart_count = 0
# 子进程启动
driver_manager.init(config=self.config) def run(self):
adapter_manager.init(self.config) load_plugins("liteyuki/plugins") # 加载轻雪插件
adapter_manager.register()
nonebot.load_plugin("src.liteyuki_main")
def _run_nb_in_spawn_process(self, *args, **kwargs): self.loop_thread.start() # 启动事件循环
""" asyncio.run(self.lifespan.before_start()) # 启动前钩子
在新的进程中运行nonebot.run方法
Args:
*args:
**kwargs:
Returns: self.process_manager.add_target("nonebot", nb_run, **self.config)
""" self.process_manager.start("nonebot")
timeout_limit: int = 20 self.process_manager.add_target("melobot", mb_run, **self.config)
should_exit = False self.process_manager.start("melobot")
while not should_exit: asyncio.run(self.lifespan.after_start()) # 启动后钩子
ctx = multiprocessing.get_context("spawn")
event = ctx.Event() self.start_watcher() # 启动文件监视器
ProcessingManager.event = event
process = ctx.Process( def start_watcher(self):
target=nb_run, if self.config.get("debug", False):
args=(event,) + args,
kwargs=kwargs, src_directories = (
"liteyuki",
"src/liteyuki_main",
"src/liteyuki_plugins",
"src/nonebot_plugins",
"src/utils",
) )
process.start() # 启动进程 src_excludes_extensions = ("pyc",)
asyncio.run(self.lifespan.after_start()) logger.debug("轻雪重载 已启用,正在加载文件修改监测……")
restart = self.restart_process
while not should_exit: class CodeModifiedHandler(FileSystemEventHandler):
if ProcessingManager.event.wait(1): """
logger.info("接收到重启活动信息") Handler for code file changes
process.terminate()
process.join(timeout_limit)
if process.is_alive():
logger.warning(
f"进程 {process.pid}{timeout_limit} 秒后依旧存在,强制清灭。"
)
process.kill()
break
elif process.is_alive():
continue
else:
should_exit = True
@staticmethod
def _run_coroutine(*coro: Coroutine):
""" """
运行协程
Args:
coro:
def on_modified(self, event):
if (
event.src_path.endswith(src_excludes_extensions)
or event.is_directory
or "__pycache__" in event.src_path
):
return
logger.info(f"文件 {event.src_path} 已修改,机器人自动重启……")
restart()
code_modified_handler = CodeModifiedHandler()
observer = Observer()
for directory in src_directories:
observer.schedule(code_modified_handler, directory, recursive=True)
observer.start()
def restart(self, delay: int = 0):
"""
重启轻雪本体
Returns: Returns:
""" """
# 检测是否有现有的事件循环
new_loop = False
try:
loop = asyncio.get_event_loop()
except RuntimeError:
new_loop = True
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if new_loop:
for c in coro:
loop.run_until_complete(c)
loop.close()
if self.call_restart_count < 1:
executable = sys.executable
args = sys.argv
logger.info("正在重启 尹灵温...")
time.sleep(delay)
if platform.system() == "Windows":
cmd = "start"
elif platform.system() == "Linux":
cmd = "nohup"
elif platform.system() == "Darwin":
cmd = "open"
else: else:
for c in coro: cmd = "nohup"
loop.create_task(c) 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
@property def restart_process(self, name: Optional[str] = None):
def status(self) -> int:
"""
获取轻雪状态
Returns:
int: 0:未启动 1:运行中
"""
return 1 if self.running else 0
def restart(self):
""" """
停止轻雪 停止轻雪
Args:
name: 进程名称, 默认为None, 所有进程
Returns: Returns:
""" """
logger.info("正在停止灵温活动…") logger.info("Stopping LiteyukiBot...")
logger.debug("正在启动 before_restart 的函数…") self.loop.create_task(self.lifespan.before_shutdown()) # 重启前钩子
self._run_coroutine(self.lifespan.before_restart()) self.loop.create_task(self.lifespan.before_shutdown()) # 停止前钩子
logger.debug("正在启动 before_shutdown 的函数…")
self._run_coroutine(self.lifespan.before_shutdown())
ProcessingManager.restart() if name:
self.running = False self.process_manager.terminate(name)
else:
self.process_manager.terminate_all()
def init(self, *args, **kwargs): def init(self, *args, **kwargs):
""" """
@ -151,20 +141,14 @@ class LiteyukiBot:
""" """
self.init_config() self.init_config()
self.init_logger() self.init_logger()
if not _MAIN_PROCESS:
nonebot.init(**kwargs)
asyncio.run(self.lifespan.after_nonebot_init())
def init_logger(self): def init_logger(self):
from src.utils.base.log import init_log # 修改nonebot的日志配置
init_log() init_log(config=self.config)
def init_config(self): def init_config(self):
pass pass
def register_adapters(self, *args):
pass
def on_before_start(self, func: LIFESPAN_FUNC): def on_before_start(self, func: LIFESPAN_FUNC):
""" """
注册启动前的函数 注册启动前的函数
@ -189,7 +173,7 @@ class LiteyukiBot:
def on_before_shutdown(self, func: LIFESPAN_FUNC): def on_before_shutdown(self, func: LIFESPAN_FUNC):
""" """
注册停止前的函数 注册停止前的函数为子进程停止时调用
Args: Args:
func: func:
@ -211,7 +195,7 @@ class LiteyukiBot:
def on_before_restart(self, func: LIFESPAN_FUNC): def on_before_restart(self, func: LIFESPAN_FUNC):
""" """
注册重启前的函数 注册重启前的函数为子进程重启时调用
Args: Args:
func: func:
@ -253,4 +237,8 @@ def get_bot() -> Optional[LiteyukiBot]:
Returns: Returns:
LiteyukiBot: 当前的轻雪实例 LiteyukiBot: 当前的轻雪实例
""" """
if IS_MAIN_PROCESS:
return _BOT_INSTANCE return _BOT_INSTANCE
else:
# 从多进程上下文中获取
pass

View File

@ -1,9 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Copyright (C) 2020-2024 LiteyukiStudio. All rights reserved Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
版权所有 © 2020-2024 神羽SnowyKami & 金羿Eilles with LiteyukiStudio & TriM Org.
保留所有权利
@Time : 2024/7/23 下午8:24 @Time : 2024/7/23 下午8:24
@Author : snowykami @Author : snowykami
@ -13,6 +10,7 @@ Copyright (C) 2020-2024 LiteyukiStudio. All rights reserved
""" """
from typing import Any, Awaitable, Callable, TypeAlias from typing import Any, Awaitable, Callable, TypeAlias
from liteyuki.log import logger
from liteyuki.utils import is_coroutine_callable from liteyuki.utils import is_coroutine_callable
SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any] SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any]
@ -138,6 +136,7 @@ class Lifespan:
启动前 启动前
Returns: Returns:
""" """
logger.debug("正在运行 before_start 之函数")
await self._run_funcs(self._before_start_funcs) await self._run_funcs(self._before_start_funcs)
async def after_start(self) -> None: async def after_start(self) -> None:
@ -145,6 +144,7 @@ class Lifespan:
启动后 启动后
Returns: Returns:
""" """
logger.debug("正在运行 after_start 之函数")
await self._run_funcs(self._after_start_funcs) await self._run_funcs(self._after_start_funcs)
async def before_shutdown(self) -> None: async def before_shutdown(self) -> None:
@ -152,6 +152,7 @@ class Lifespan:
停止前 停止前
Returns: Returns:
""" """
logger.debug("正在运行 before_shutdown 之函数")
await self._run_funcs(self._before_shutdown_funcs) await self._run_funcs(self._before_shutdown_funcs)
async def after_shutdown(self) -> None: async def after_shutdown(self) -> None:
@ -159,6 +160,7 @@ class Lifespan:
停止后 停止后
Returns: Returns:
""" """
logger.debug("正在运行 after_shutdown 之函数")
await self._run_funcs(self._after_shutdown_funcs) await self._run_funcs(self._after_shutdown_funcs)
async def before_restart(self) -> None: async def before_restart(self) -> None:
@ -166,6 +168,7 @@ class Lifespan:
重启前 重启前
Returns: Returns:
""" """
logger.debug("正在运行 before_restart 之函数")
await self._run_funcs(self._before_restart_funcs) await self._run_funcs(self._before_restart_funcs)
async def after_restart(self) -> None: async def after_restart(self) -> None:
@ -174,6 +177,7 @@ class Lifespan:
Returns: Returns:
""" """
logger.debug("正在运行 after_restart 之函数")
await self._run_funcs(self._after_restart_funcs) await self._run_funcs(self._after_restart_funcs)
async def after_nonebot_init(self) -> None: async def after_nonebot_init(self) -> None:
@ -181,4 +185,5 @@ class Lifespan:
NoneBot 初始化后 NoneBot 初始化后
Returns: Returns:
""" """
logger.debug("正在运行 after_nonebot_init 之函数")
await self._run_funcs(self._after_nonebot_init_funcs) await self._run_funcs(self._after_nonebot_init_funcs)

30
liteyuki/comm/__init__.py Normal file
View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/26 下午10:36
@Author : snowykami
@Email : snowykami@outlook.com
@File : __init__.py
@Software: PyCharm
该模块用于轻雪主进程和Nonebot子进程之间的通信
"""
from liteyuki.comm.channel import (
Channel,
chan,
get_channel,
set_channel,
set_channels,
get_channels
)
from liteyuki.comm.event import Event
__all__ = [
"Channel",
"chan",
"Event",
"get_channel",
"set_channel",
"set_channels",
"get_channels"
]

219
liteyuki/comm/channel.py Normal file
View File

@ -0,0 +1,219 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/26 下午11:21
@Author : snowykami
@Email : snowykami@outlook.com
@File : channel.py
@Software: PyCharm
本模块定义了一个通用的通道类用于进程间通信
"""
import functools
import multiprocessing
import threading
from multiprocessing import Pipe
from typing import Any, Optional, Callable, Awaitable, List, TypeAlias
from uuid import uuid4
from liteyuki.utils import is_coroutine_callable, run_coroutine
SYNC_ON_RECEIVE_FUNC: TypeAlias = Callable[[Any], Any]
ASYNC_ON_RECEIVE_FUNC: TypeAlias = Callable[[Any], Awaitable[Any]]
ON_RECEIVE_FUNC: TypeAlias = SYNC_ON_RECEIVE_FUNC | ASYNC_ON_RECEIVE_FUNC
SYNC_FILTER_FUNC: TypeAlias = Callable[[Any], bool]
ASYNC_FILTER_FUNC: TypeAlias = Callable[[Any], Awaitable[bool]]
FILTER_FUNC: TypeAlias = SYNC_FILTER_FUNC | ASYNC_FILTER_FUNC
IS_MAIN_PROCESS = multiprocessing.current_process().name == "MainProcess"
_channel: dict[str, "Channel"] = {}
_callback_funcs: dict[str, ON_RECEIVE_FUNC] = {}
class Channel:
"""
通道类用于进程间通信进程内不可用仅限主进程和子进程之间通信
有两种接收工作方式但是只能选择一种主动接收和被动接收主动接收使用 `receive` 方法被动接收使用 `on_receive` 装饰器
"""
def __init__(self, _id: str):
self.main_send_conn, self.sub_receive_conn = Pipe()
self.sub_send_conn, self.main_receive_conn = Pipe()
self._closed = False
self._on_main_receive_funcs: list[str] = []
self._on_sub_receive_funcs: list[str] = []
self.name: str = _id
self.is_main_receive_loop_running = False
self.is_sub_receive_loop_running = False
def __str__(self):
return f"Channel({self.name})"
def send(self, data: Any):
"""
发送数据
Args:
data: 数据
"""
if self._closed:
raise RuntimeError("无法发送至已关闭的通道中")
if IS_MAIN_PROCESS:
print("主进程发送数据:", data)
self.main_send_conn.send(data)
else:
print("子进程发送数据:", data)
self.sub_send_conn.send(data)
def receive(self) -> Any:
"""
接收数据
Args:
"""
if self._closed:
raise RuntimeError("无法从已关闭的通道中接收")
while True:
# 判断receiver是否为None或者receiver是否等于接收者是则接收数据否则不动数据
if IS_MAIN_PROCESS:
data = self.main_receive_conn.recv()
print("主进程接收数据:", data)
else:
data = self.sub_receive_conn.recv()
print("子进程接收数据:", data)
return data
def close(self):
"""
关闭通道
"""
self._closed = True
self.sub_receive_conn.close()
self.main_send_conn.close()
self.sub_send_conn.close()
self.main_receive_conn.close()
def on_receive(self, filter_func: Optional[FILTER_FUNC] = None) -> Callable[[ON_RECEIVE_FUNC], ON_RECEIVE_FUNC]:
"""
接收数据并执行函数
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).start()
if (not self.is_main_receive_loop_running) and IS_MAIN_PROCESS:
threading.Thread(target=self._start_main_receive_loop).start()
def decorator(func: ON_RECEIVE_FUNC) -> ON_RECEIVE_FUNC:
async def wrapper(data: Any) -> Any:
if filter_func is not None:
if is_coroutine_callable(filter_func):
if not await filter_func(data):
return
else:
if not filter_func(data):
return
return await func(data)
function_id = str(uuid4())
_callback_funcs[function_id] = wrapper
if IS_MAIN_PROCESS:
self._on_main_receive_funcs.append(function_id)
else:
self._on_sub_receive_funcs.append(function_id)
return func
return decorator
def _run_on_main_receive_funcs(self, data: Any):
"""
运行接收函数
Args:
data: 数据
"""
for func_id in self._on_main_receive_funcs:
func = _callback_funcs[func_id]
run_coroutine(func(data))
def _run_on_sub_receive_funcs(self, data: Any):
"""
运行接收函数
Args:
data: 数据
"""
for func_id in self._on_sub_receive_funcs:
func = _callback_funcs[func_id]
run_coroutine(func(data))
def _start_main_receive_loop(self):
"""
开始接收数据
"""
self.is_main_receive_loop_running = True
while not self._closed:
data = self.main_receive_conn.recv()
self._run_on_main_receive_funcs(data)
def _start_sub_receive_loop(self):
"""
开始接收数据
"""
self.is_sub_receive_loop_running = True
while not self._closed:
data = self.sub_receive_conn.recv()
self._run_on_sub_receive_funcs(data)
def __iter__(self):
return self
def __next__(self) -> Any:
return self.receive()
"""默认通道实例,可直接从模块导入使用"""
chan = Channel("default")
def set_channel(name: str, channel: Channel):
"""
设置通道实例
Args:
name: 通道名称
channel: 通道实例
"""
_channel[name] = channel
def set_channels(channels: dict[str, Channel]):
"""
设置通道实例
Args:
channels: 通道名称
"""
for name, channel in channels.items():
_channel[name] = channel
def get_channel(name: str) -> Optional[Channel]:
"""
获取通道实例
Args:
name: 通道名称
Returns:
"""
return _channel.get(name, None)
def get_channels() -> dict[str, Channel]:
"""
获取通道实例
Returns:
"""
return _channel

21
liteyuki/comm/event.py Normal file
View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/26 下午10:47
@Author : snowykami
@Email : snowykami@outlook.com
@File : event.py
@Software: PyCharm
"""
from typing import Any
class Event:
"""
事件类
"""
def __init__(self, name: str, data: dict[str, Any]):
self.name = name
self.data = data

View File

@ -0,0 +1,49 @@
import os
from typing import List
import nonebot
import yaml
from pydantic import BaseModel
config = {} # 主进程全局配置,确保加载后读取
class SatoriNodeConfig(BaseModel):
host: str = ""
port: str = "5500"
path: str = ""
token: str = ""
class SatoriConfig(BaseModel):
comment: str = "此皆正处于开发之中,切勿在生产环境中启用。"
enable: bool = False
hosts: List[SatoriNodeConfig] = [SatoriNodeConfig()]
class BasicConfig(BaseModel):
host: str = "127.0.0.1"
port: int = 20247
superusers: list[str] = []
command_start: list[str] = ["/", ""]
nickname: list[str] = [f"灵温"]
satori: SatoriConfig = SatoriConfig()
data_path: str = "data/liteyuki"
def load_from_yaml(file: str) -> dict:
global config
nonebot.logger.debug("Loading config from %s" % file)
if not os.path.exists(file):
nonebot.logger.warning(f"未找到配置文件 {file} ,已创建默认配置,请修改后重启。")
with open(file, "w", encoding="utf-8") as f:
yaml.dump(BasicConfig().dict(), f, default_flow_style=False)
with open(file, "r", encoding="utf-8") as f:
conf = yaml.load(f, Loader=yaml.FullLoader)
config = conf
if conf is None:
nonebot.logger.warning(f"配置文件 {file} 为空,已创建默认配置,请修改后重启。")
conf = BasicConfig().dict()
return conf

View File

@ -1,3 +1,11 @@
import multiprocessing
from .spawn_process import * from .spawn_process import *
from .manager import *
__all__ = [
"IS_MAIN_PROCESS"
]
IS_MAIN_PROCESS = multiprocessing.current_process().name == "MainProcess"

120
liteyuki/core/manager.py Normal file
View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/27 上午11:12
@Author : snowykami
@Email : snowykami@outlook.com
@File : manager.py
@Software: PyCharm
"""
import asyncio
import threading
from multiprocessing import Process
from typing import TYPE_CHECKING
from liteyuki.comm import Channel, get_channel, set_channels
from liteyuki.log import logger
if TYPE_CHECKING:
from liteyuki.bot import LiteyukiBot
TIMEOUT = 10
__all__ = ["ProcessManager"]
class ProcessManager:
"""
在主进程中被调用
"""
def __init__(self, bot: "LiteyukiBot"):
self.bot = bot
self.targets: dict[str, tuple[callable, tuple, dict]] = {}
self.processes: dict[str, Process] = {}
set_channels(
{
"nonebot-active": Channel(_id="nonebot-active"),
"melobot-active": Channel(_id="melobot-active"),
"nonebot-passive": Channel(_id="nonebot-passive"),
"melobot-passive": Channel(_id="melobot-passive"),
}
)
def start(self, name: str, delay: int = 0):
"""
开启后自动监控进程并添加到进程字典中
Args:
name:
delay:
Returns:
"""
if name not in self.targets:
raise KeyError(f"未有 Process {name} 之存在")
def _start():
should_exit = False
while not should_exit:
chan_active = get_channel(f"{name}-active")
chan_passive = get_channel(f"{name}-passive")
process = Process(
target=self.targets[name][0],
args=(chan_active, chan_passive, *self.targets[name][1]),
kwargs=self.targets[name][2],
)
self.processes[name] = process
process.start()
while not should_exit:
# 0退出 1重启
data = chan_active.receive()
if data == 1:
logger.info(f"重启 {name} 进程")
asyncio.run(self.bot.lifespan.before_shutdown())
asyncio.run(self.bot.lifespan.before_restart())
self.terminate(name)
break
elif data == 0:
logger.info(f"关停 {name} 进程")
asyncio.run(self.bot.lifespan.before_shutdown())
should_exit = True
self.terminate(name)
else:
logger.warning("数据未知,省略:{}".format(data))
if delay:
threading.Timer(delay, _start).start()
else:
threading.Thread(target=_start).start()
def add_target(self, name: str, target, *args, **kwargs):
self.targets[name] = (target, args, kwargs)
def join(self):
for name, process in self.targets:
process.join()
def terminate(self, name: str):
"""
终止进程并从进程字典中删除
Args:
name:
Returns:
"""
if name not in self.targets:
raise logger.warning(f"未有 Process {name} 之存在")
process = self.processes[name]
process.terminate()
process.join(TIMEOUT)
if process.is_alive():
process.kill()
def terminate_all(self):
for name in self.targets:
self.terminate(name)

View File

@ -1,37 +1,56 @@
import threading from typing import Optional, TYPE_CHECKING
from multiprocessing import get_context, Event
import nonebot import nonebot
from nonebot import logger
from liteyuki.plugin.load import load_plugins from liteyuki.core.nb import adapter_manager, driver_manager
from liteyuki.comm.channel import set_channel
if TYPE_CHECKING:
from liteyuki.comm.channel import Channel
timeout_limit: int = 20 timeout_limit: int = 20
__all__ = [
"ProcessingManager", """导出对象用于主进程与nonebot通信"""
"nb_run", _channels = {}
]
class ProcessingManager: def nb_run(chan_active: "Channel", chan_passive: "Channel", *args, **kwargs):
event: Event = None
@classmethod
def restart(cls, delay: int = 0):
""" """
发送终止信号 初始化NoneBot并运行在子进程
Args: Args:
delay: 延迟时间默认为0单位秒
chan_active:
chan_passive:
**kwargs:
Returns: Returns:
""" """
if cls.event is None: set_channel("nonebot-active", chan_active)
raise RuntimeError("ProcessingManager 未初始化。") set_channel("nonebot-passive", chan_passive)
if delay > 0: nonebot.init(**kwargs)
threading.Timer(delay, function=cls.event.set).start() driver_manager.init(config=kwargs)
return adapter_manager.init(kwargs)
cls.event.set() adapter_manager.register()
nonebot.load_plugin("src.liteyuki_main")
nonebot.run()
def nb_run(event, *args, **kwargs): def mb_run(chan_active: "Channel", chan_passive: "Channel", *args, **kwargs):
ProcessingManager.event = event """
nonebot.run(*args, **kwargs) 初始化MeloBot并运行在子进程
Args:
chan_active
chan_passive
*args:
**kwargs:
Returns:
"""
set_channel("melobot-active", chan_active)
set_channel("melobot-passive", chan_passive)
# bot = MeloBot(__name__)
# bot.init(AbstractConnector(cd_time=0))
# bot.run()

84
liteyuki/log.py Normal file
View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/27 上午9:12
@Author : snowykami
@Email : snowykami@outlook.com
@File : log.py
@Software: PyCharm
"""
import sys
import loguru
from typing import TYPE_CHECKING
logger = loguru.logger
if TYPE_CHECKING:
# avoid sphinx autodoc resolve annotation failed
# because loguru module do not have `Logger` class actually
from loguru import Record
def default_filter(record: "Record"):
"""默认的日志过滤器,根据 `config.log_level` 配置改变日志等级。"""
log_level = record["extra"].get("nonebot_log_level", "INFO")
levelno = logger.level(log_level).no if isinstance(log_level, str) else log_level
return record["level"].no >= levelno
# DEBUG日志格式
debug_format: str = (
"<c>{time:YYYY-MM-DD HH:mm:ss}</c> "
"<lvl>[{level.icon}]</lvl> "
"<c><{name}.{module}.{function}:{line}></c> "
"{message}"
)
# 默认日志格式
default_format: str = (
"<c>{time:MM-DD HH:mm:ss}</c> "
"<lvl>[{level.icon}]</lvl> "
"<c><{name}></c> "
"{message}"
)
def get_format(level: str) -> str:
if level == "DEBUG":
return debug_format
else:
return default_format
logger = loguru.logger.bind()
def init_log(config: dict):
"""
在语言加载完成后执行
Returns:
"""
global logger
logger.remove()
logger.add(
sys.stdout,
level=0,
diagnose=False,
filter=default_filter,
format=get_format(config.get("log_level", "INFO")),
)
show_icon = config.get("log_icon", True)
# debug = lang.get("log.debug", default="==DEBUG")
# info = lang.get("log.info", default="===INFO")
# success = lang.get("log.success", default="SUCCESS")
# warning = lang.get("log.warning", default="WARNING")
# error = lang.get("log.error", default="==ERROR")
#
# logger.level("DEBUG", color="<blue>", icon=f"{'🐛' if show_icon else ''}{debug}")
# logger.level("INFO", color="<normal>", icon=f"{'' if show_icon else ''}{info}")
# logger.level("SUCCESS", color="<green>", icon=f"{'✅' if show_icon else ''}{success}")
# logger.level("WARNING", color="<yellow>", icon=f"{'⚠️' if show_icon else ''}{warning}")
# logger.level("ERROR", color="<red>", icon=f"{'⭕' if show_icon else ''}{error}")

View File

@ -1,10 +1,11 @@
from liteyuki.plugin.model import Plugin, PluginMetadata from liteyuki.plugin.model import Plugin, PluginMetadata
from liteyuki.plugin.load import load_plugin, _plugins from liteyuki.plugin.load import load_plugin, load_plugins, _plugins
__all__ = [ __all__ = [
"PluginMetadata", "PluginMetadata",
"Plugin", "Plugin",
"load_plugin", "load_plugin",
"load_plugins",
] ]

View File

@ -1,9 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Copyright (C) 2020-2024 LiteyukiStudio. All rights reserved Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
版权所有 © 2020-2024 神羽SnowyKami & 金羿Eilles with LiteyukiStudio & TriM Org.
保留所有权利
@Time : 2024/7/23 下午11:59 @Time : 2024/7/23 下午11:59
@Author : snowykami @Author : snowykami
@ -25,6 +22,11 @@ from liteyuki.utils import path_to_module_name
_plugins: dict[str, Plugin] = {} _plugins: dict[str, Plugin] = {}
__all__ = [
"load_plugin",
"load_plugins",
]
def load_plugin(module_path: str | Path) -> Optional[Plugin]: def load_plugin(module_path: str | Path) -> Optional[Plugin]:
"""加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。 """加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。

View File

@ -1,9 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Copyright (C) 2020-2024 LiteyukiStudio. All rights reserved Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
版权所有 © 2020-2024 神羽SnowyKami & 金羿Eilles with LiteyukiStudio & TriM Org.
保留所有权利
@Time : 2024/7/24 上午12:02 @Time : 2024/7/24 上午12:02
@Author : snowykami @Author : snowykami
@ -19,10 +16,10 @@ from pydantic import BaseModel
class PluginMetadata(BaseModel): class PluginMetadata(BaseModel):
""" """
轻雪插件元数据由插件编写者提供 轻雪插件元数据由插件编写者提供name为必填项
""" """
name: str name: str
description: str description: str = ""
usage: str = "" usage: str = ""
type: str = "" type: str = ""
homepage: str = "" homepage: str = ""

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
#
# @Time : 2024/7/22 上午11:25
# @Author : snowykami
# @Email : snowykami@outlook.com
# @File : asa.py
# @Software: PyCharm
import asyncio
from liteyuki.plugin import PluginMetadata
from liteyuki import get_bot, logger
from liteyuki.comm.channel import get_channel
__plugin_meta__ = PluginMetadata(
name="lifespan_monitor",
)
bot = get_bot()
nbp_chan = get_channel("nonebot-passive")
mbp_chan = get_channel("melobot-passive")
@bot.on_before_start
def _():
logger.info("生命周期监控器:启动前")
@bot.on_before_shutdown
def _():
print(get_channel("main"))
logger.info("生命周期监控器:停止前")
@bot.on_before_restart
def _():
logger.info("生命周期监控器:重启前")
@bot.on_after_start
def _():
logger.info("生命周期监控器:启动后")
@bot.on_after_start
async def _():
logger.info("生命周期监控器:启动后")
# @mbp_chan.on_receive()
# @nbp_chan.on_receive()
# async def _(data):
# print("主进程收到数据", data)

View File

@ -1,41 +0,0 @@
import multiprocessing
import time
import nonebot
from nonebot import get_driver
from liteyuki.plugin import PluginMetadata
from liteyuki import get_bot
__plugin_metadata__ = PluginMetadata(
name="plugin_loader",
description="轻雪插件加载器",
usage="",
type="",
homepage=""
)
from src.utils import TempConfig, common_db
liteyuki = get_bot()
@liteyuki.on_after_start
def _():
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
# 储存重启计时信息
if temp_data.data.get("reload", False):
delta_time = time.time() - temp_data.data.get("reload_time", 0)
temp_data.data["delta_time"] = delta_time
common_db.save(temp_data) # 更新数据
@liteyuki.on_before_start
def _():
print("灵温正在启动")
@liteyuki.on_after_nonebot_init
async def _():
print("NoneBot初始化完成")
nonebot.load_plugin("src.liteyuki_main")

View File

@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All rights reserved
版权所有 © 2020-2024 神羽SnowyKami & 金羿Eilles with LiteyukiStudio & TriM Org.
保留所有权利
@Time : 2024/7/23 下午11:21
@Author : snowykami
@Email : snowykami@outlook.com
@File : data_source.py
@Software: PyCharm
"""

View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/10 下午11:25
@Author : snowykami
@Email : snowykami@outlook.com
@File : register_service.py
@Software: PyCharm
"""
import json
import os.path
import platform
import requests
from git import Repo
from liteyuki.plugin import PluginMetadata
from liteyuki import get_bot, logger
__plugin_meta__ = PluginMetadata(
name="注册服务",
)
liteyuki = get_bot()
commit_hash = Repo(".").head.commit.hexsha
def register_bot():
url = "https://api.liteyuki.icu/register"
data = {
"name" : "尹灵温|轻雪-睿乐",
"version" : "即时更新",
"hash" : commit_hash,
"version_i": 99,
"python" : f"{platform.python_implementation()} {platform.python_version()}",
"os" : f"{platform.system()} {platform.version()} {platform.machine()}"
}
try:
logger.info("正在等待 Liteyuki 注册服务器……")
resp = requests.post(url, json=data, timeout=(10, 15))
if resp.status_code == 200:
data = resp.json()
if liteyuki_id := data.get("liteyuki_id"):
with open("data/liteyuki/liteyuki.json", "wb") as f:
f.write(json.dumps(data).encode("utf-8"))
logger.success("成功将 {} 注册到 Liteyuki 服务器".format(liteyuki_id))
else:
raise ValueError(f"无法向 Liteyuki 服务器注册:{data}")
except Exception as e:
logger.warning(f"虽然向 Liteyuki 服务器注册失败,但无关紧要:{e}")
@liteyuki.on_before_start
async def _():
if not os.path.exists("data/liteyuki/liteyuki.json"):
register_bot()

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/8/10 下午5:18
@Author : snowykami
@Email : snowykami@outlook.com
@File : reloader_monitor.py
@Software: PyCharm
"""

View File

@ -2,9 +2,12 @@
""" """
一些常用的工具类部分来源于 nonebot 并遵循其许可进行修改 一些常用的工具类部分来源于 nonebot 并遵循其许可进行修改
""" """
import asyncio
import inspect import inspect
from pathlib import Path from pathlib import Path
from typing import Any, Callable from typing import Any, Callable, Coroutine
from liteyuki.log import logger
def is_coroutine_callable(call: Callable[..., Any]) -> bool: def is_coroutine_callable(call: Callable[..., Any]) -> bool:
@ -23,6 +26,39 @@ def is_coroutine_callable(call: Callable[..., Any]) -> bool:
return inspect.iscoroutinefunction(func_) return inspect.iscoroutinefunction(func_)
def run_coroutine(*coro: Coroutine):
"""
运行协程
Args:
coro:
Returns:
"""
# 检测是否有现有的事件循环
try:
loop = asyncio.get_event_loop()
if loop.is_running():
# 如果事件循环正在运行,创建任务
for c in coro:
asyncio.ensure_future(c)
else:
# 如果事件循环未运行,运行直到完成
for c in coro:
loop.run_until_complete(c)
except RuntimeError:
# 如果没有找到事件循环,创建一个新的
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(asyncio.gather(*coro))
loop.close()
except Exception as e:
# 捕获其他异常,防止协程被重复等待
logger.error(f"协程异常:{e}")
def path_to_module_name(path: Path) -> str: def path_to_module_name(path: Path) -> str:
""" """
转换路径为模块名 转换路径为模块名

View File

@ -1,6 +1,6 @@
from liteyuki import LiteyukiBot from liteyuki import LiteyukiBot
from src.utils import load_from_yaml from liteyuki.config import load_from_yaml
if __name__ in ("__main__", "__mp_main__"): if __name__ == "__main__":
bot = LiteyukiBot(**load_from_yaml("config.yml")) bot = LiteyukiBot(**load_from_yaml("config.yml"))
bot.run() bot.run()

View File

@ -4,30 +4,27 @@ from typing import Any, AnyStr
import nonebot import nonebot
import pip import pip
from nonebot import Bot, get_driver, require from nonebot import Bot, get_driver, require # type: ignore
from nonebot.adapters import satori from nonebot.adapters import onebot, satori
from nonebot.adapters.onebot.v11 import Message, escape, unescape from nonebot.adapters.onebot.v11 import Message, escape, unescape
from nonebot.exception import MockApiException from nonebot.exception import MockApiException
from nonebot.internal.matcher import Matcher from nonebot.internal.matcher import Matcher
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from src.utils import event as event_utils, satori_utils
from src.utils.base.config import get_config, load_from_yaml from src.utils.base.config import get_config, load_from_yaml
from src.utils.base.data_manager import StoredConfig, TempConfig, common_db from src.utils.base.data_manager import StoredConfig, TempConfig, common_db
from src.utils.base.language import get_user_lang from src.utils.base.language import get_user_lang
from src.utils.base.ly_typing import T_Bot, T_MessageEvent from src.utils.base.ly_typing import T_Bot, T_MessageEvent
from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers from src.utils.message.message import MarkdownMessage as md, broadcast_to_superusers
# from src.liteyuki.core import Reloader
from src.utils import event as event_utils, satori_utils
from liteyuki.core import ProcessingManager
from .api import update_liteyuki from .api import update_liteyuki
from liteyuki.bot import get_bot from ..utils.base import reload
from ..utils.base.ly_function import get_function from ..utils.base.ly_function import get_function
require("nonebot_plugin_alconna") require("nonebot_plugin_alconna")
require("nonebot_plugin_apscheduler") require("nonebot_plugin_apscheduler")
from nonebot_plugin_alconna import ( from nonebot_plugin_alconna import (
UniMessage,
on_alconna, on_alconna,
Alconna, Alconna,
Args, Args,
@ -111,16 +108,15 @@ async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
"reload_session_id": ( "reload_session_id": (
(event.group_id if event.message_type == "group" else event.user_id) (event.group_id if event.message_type == "group" else event.user_id)
if not isinstance(event, satori.event.Event) if not isinstance(event, satori.event.Event)
else event.channel.id else event.chan_active.id
), ),
"delta_time": 0, "delta_time": 0,
} }
) )
common_db.save(temp_data) common_db.save(temp_data)
# Reloader.reload(0)
bot = get_bot() reload()
bot.restart()
@on_alconna( @on_alconna(
@ -380,20 +376,18 @@ async def test_for_md_image(bot: T_Bot, api: str, data: dict):
@driver.on_startup @driver.on_startup
async def on_startup(): async def on_startup():
# temp_data = common_db.where_one(TempConfig(), default=TempConfig()) temp_data = common_db.where_one(TempConfig(), default=TempConfig())
# # 储存重启信息 # 储存重启信息
# if temp_data.data.get("reload", False): if temp_data.data.get("reload", False):
# delta_time = time.time() - temp_data.data.get("reload_time", 0) delta_time = time.time() - temp_data.data.get("reload_time", 0)
# temp_data.data["delta_time"] = delta_time temp_data.data["delta_time"] = delta_time
# common_db.save(temp_data) # 更新数据 common_db.save(temp_data) # 更新数据
""" """
该部分迁移至轻雪生命周期 该部分迁移至轻雪生命周期
Returns: Returns:
""" """
pass
@driver.on_shutdown @driver.on_shutdown
async def on_shutdown(): async def on_shutdown():
@ -415,10 +409,22 @@ async def _(bot: T_Bot):
reload_session_id = temp_data.data.get("reload_session_id", 0) reload_session_id = temp_data.data.get("reload_session_id", 0)
delta_time = temp_data.data.get("delta_time", 0) delta_time = temp_data.data.get("delta_time", 0)
common_db.save(temp_data) # 更新数据 common_db.save(temp_data) # 更新数据
return_msg = "轻雪核心 重载耗时 {:.2f}\n灵温 预计体感重载耗时 {:.2f}\n*此数据仅作参考,具体计时请以实际为准".format(
delta_time, time.time() - temp_data.data.get("reload_time", 0)
)
if isinstance(bot, satori.Bot): if isinstance(bot, satori.Bot):
await bot.send_message( await bot.send_message(
channel_id=reload_session_id, channel_id=reload_session_id,
message="轻雪核心 重载耗时 {:.2f}\n*此数据仅作参考,具体计时请以实际为准\n灵温 预计体感重载耗时 {:.2f}".format(delta_time,time.time() - temp_data.data.get("reload_time", 0)), message=return_msg,
)
elif isinstance(bot, onebot.v11.Bot):
await bot.send_msg(
message_type=reload_session_type,
user_id=reload_session_id,
group_id=reload_session_id,
message=return_msg,
) )
else: else:
await bot.call_api( await bot.call_api(
@ -426,7 +432,7 @@ async def _(bot: T_Bot):
message_type=reload_session_type, message_type=reload_session_type,
user_id=reload_session_id, user_id=reload_session_id,
group_id=reload_session_id, group_id=reload_session_id,
message="轻雪核心 重载耗时 {:.2f}\n*此数据仅作参考,具体计时请以实际为准\n灵温 预计体感重载耗时 {:.2f}".format(delta_time,time.time() - temp_data.data.get("reload_time", 0)), message=return_msg,
) )
@ -439,7 +445,8 @@ async def every_day_update():
if result: if result:
await broadcast_to_superusers(f"灵温已更新:```\n{logs}\n```") await broadcast_to_superusers(f"灵温已更新:```\n{logs}\n```")
nonebot.logger.info(f"灵温已更新:{logs}") nonebot.logger.info(f"灵温已更新:{logs}")
ProcessingManager.restart(3) # ProcessingManager.restart(3)
reload()
else: else:
nonebot.logger.info(logs) nonebot.logger.info(logs)

View File

@ -3,58 +3,31 @@ from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
from liteyuki.bot import get_bot from liteyuki.bot import get_bot
from src.utils.base import reload
from src.utils.base.config import get_config from src.utils.base.config import get_config
from liteyuki.core import ProcessingManager
from src.utils.base.resource import load_resources from src.utils.base.resource import load_resources
if get_config("debug", False): if get_config("debug", False):
liteyuki_bot = get_bot() liteyuki_bot = get_bot()
src_directories = (
"src/liteyuki_main",
"src/plugins",
"src/utils",
)
src_excludes_extensions = ("pyc",)
res_directories = ( res_directories = (
"src/resources", "src/resources",
"resources", "resources",
) )
nonebot.logger.info("已启用 Liteyuki Reload ,正在监测文件变动。")
class CodeModifiedHandler(FileSystemEventHandler):
"""
Handler for code file changes
"""
def on_modified(self, event):
if (
event.src_path.endswith(src_excludes_extensions)
or event.is_directory
or "__pycache__" in event.src_path
):
return
nonebot.logger.info(f"文件 {event.src_path} 变更,正在重载…")
liteyuki_bot.restart()
class ResourceModifiedHandler(FileSystemEventHandler): class ResourceModifiedHandler(FileSystemEventHandler):
""" """
Handler for resource file changes Handler for resource file changes
""" """
def on_modified(self, event): def on_modified(self, event):
nonebot.logger.info(f"资源 {event.src_path} 变更,重载资源包…") nonebot.logger.info(f"资源 {event.src_path} 变更,重载资源包……")
load_resources() load_resources()
code_modified_handler = CodeModifiedHandler()
resource_modified_handle = ResourceModifiedHandler() resource_modified_handle = ResourceModifiedHandler()
observer = Observer() observer = Observer()
for directory in src_directories:
observer.schedule(code_modified_handler, directory, recursive=True)
for directory in res_directories: for directory in res_directories:
observer.schedule(resource_modified_handle, directory, recursive=True) observer.schedule(resource_modified_handle, directory, recursive=True)
observer.start() observer.start()

View File

@ -1,3 +1,5 @@
import asyncio
import nonebot.plugin import nonebot.plugin
from nonebot import get_driver from nonebot import get_driver
from src.utils import init_log from src.utils import init_log
@ -6,7 +8,9 @@ from src.utils.base.data_manager import InstalledPlugin, plugin_db
from src.utils.base.resource import load_resources from src.utils.base.resource import load_resources
from src.utils.message.tools import check_for_package from src.utils.message.tools import check_for_package
from liteyuki import get_bot from liteyuki import get_bot, chan
from nonebot_plugin_apscheduler import scheduler
load_resources() load_resources()
init_log() init_log()
@ -17,7 +21,7 @@ liteyuki_bot = get_bot()
@driver.on_startup @driver.on_startup
async def load_plugins(): async def load_plugins():
nonebot.plugin.load_plugins("src/plugins") nonebot.plugin.load_plugins("src/nonebot_plugins")
# 从数据库读取已安装的插件 # 从数据库读取已安装的插件
if not get_config("safe_mode", False): if not get_config("safe_mode", False):
# 安全模式下,不加载插件 # 安全模式下,不加载插件
@ -34,34 +38,4 @@ async def load_plugins():
nonebot.load_plugin(installed_plugin.module_name) nonebot.load_plugin(installed_plugin.module_name)
nonebot.plugin.load_plugins("plugins") nonebot.plugin.load_plugins("plugins")
else: else:
nonebot.logger.info("安全模式已启动,未加载任何插件。") nonebot.logger.info("当前处于安全模式,未加载任何插件。")
@liteyuki_bot.on_before_start
async def _():
print("启动前")
@liteyuki_bot.on_after_start
async def _():
print("启动后")
@liteyuki_bot.on_before_shutdown
async def _():
print("停止前")
@liteyuki_bot.on_after_shutdown
async def _():
print("停止后")
@liteyuki_bot.on_before_restart
async def _():
print("重启前")
@liteyuki_bot.on_after_restart
async def _():
print("重启后")

View File

@ -0,0 +1,3 @@
# 说明
此目录为**轻雪插件**目录,非其他插件目录。

View File

@ -1,7 +1,7 @@
import multiprocessing import multiprocessing
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from liteyuki.plugin import get_loaded_plugins from liteyuki.comm import get_channel
from .rt_guide import * from .rt_guide import *
from .crt_matchers import * from .crt_matchers import *
@ -18,4 +18,10 @@ __plugin_meta__ = PluginMetadata(
} }
) )
print("已加载插件:", len(get_loaded_plugins())) # chan = get_channel("nonebot-passive")
#
#
# @chan.on_receive()
# async def _(d):
# print("CRT子进程接收到数据", d)
# chan.send("CRT子进程已接收到数据")

View File

@ -153,7 +153,6 @@ class Minesweeper:
text += "\n\n" text += "\n\n"
for i, row in enumerate(self.board): for i, row in enumerate(self.board):
text += start + f"{self.NUMS[i]}" + dis*2 text += start + f"{self.NUMS[i]}" + dis*2
print([d.value for d in row])
for dot in row: for dot in row:
if dot.mask and not dot.flagged: if dot.mask and not dot.flagged:
text += md.btn_cmd(self.MASK, f"minesweeper reveal {dot.row} {dot.col}") text += md.btn_cmd(self.MASK, f"minesweeper reveal {dot.row} {dot.col}")

View File

@ -7,7 +7,14 @@ from nonebot.adapters import satori
from src.utils import event as event_utils from src.utils import event as event_utils
from src.utils.base.data import LiteModel from src.utils.base.data import LiteModel
from src.utils.base.data_manager import GlobalPlugin, Group, User, group_db, plugin_db, user_db from src.utils.base.data_manager import (
GlobalPlugin,
Group,
User,
group_db,
plugin_db,
user_db,
)
from src.utils.base.ly_typing import T_MessageEvent from src.utils.base.ly_typing import T_MessageEvent
__group_data = {} # 群数据缓存, {group_id: Group} __group_data = {} # 群数据缓存, {group_id: Group}
@ -18,13 +25,15 @@ __global_enable = {} # 插件全局启用状态缓存, {plugin_name: bool} dyna
class PluginTag(LiteModel): class PluginTag(LiteModel):
label: str label: str
color: str = '#000000' color: str = "#000000"
class StorePlugin(LiteModel): class StorePlugin(LiteModel):
name: str name: str
desc: str desc: str
module_name: str # 插件商店中的模块名不等于本地的模块名,前者是文件夹名,后者是点分割模块名 module_name: (
str # 插件商店中的模块名不等于本地的模块名,前者是文件夹名,后者是点分割模块名
)
project_link: str = "" project_link: str = ""
homepage: str = "" homepage: str = ""
author: str = "" author: str = ""
@ -61,7 +70,9 @@ async def get_store_plugin(plugin_name: str) -> Optional[StorePlugin]:
Optional[StorePlugin]: 插件信息 Optional[StorePlugin]: 插件信息
""" """
async with aiofiles.open("data/liteyuki/plugins.json", "r", encoding="utf-8") as f: async with aiofiles.open("data/liteyuki/plugins.json", "r", encoding="utf-8") as f:
plugins: list[StorePlugin] = [StorePlugin(**pobj) for pobj in json.loads(await f.read())] plugins: list[StorePlugin] = [
StorePlugin(**pobj) for pobj in json.loads(await f.read())
]
for plugin in plugins: for plugin in plugins:
if plugin.module_name == plugin_name: if plugin.module_name == plugin_name:
return plugin return plugin
@ -80,7 +91,11 @@ def get_plugin_default_enable(plugin_name: str) -> bool:
""" """
if plugin_name not in __default_enable: if plugin_name not in __default_enable:
plug = nonebot.plugin.get_plugin(plugin_name) plug = nonebot.plugin.get_plugin(plugin_name)
default_enable = (plug.metadata.extra.get("default_enable", True) if plug.metadata else True) if plug else True default_enable = (
(plug.metadata.extra.get("default_enable", True) if plug.metadata else True)
if plug
else True
)
__default_enable[plugin_name] = default_enable __default_enable[plugin_name] = default_enable
return __default_enable[plugin_name] return __default_enable[plugin_name]
@ -105,17 +120,25 @@ def get_plugin_session_enable(event: T_MessageEvent, plugin_name: str) -> bool:
else: else:
message_type = event.message_type message_type = event.message_type
if message_type == "group": if message_type == "group":
group_id = str(event.guild.id if isinstance(event, satori.event.Event) else event.group_id) group_id = str(
event.guild.id if isinstance(event, satori.event.Event) else event.group_id
)
if group_id not in __group_data: if group_id not in __group_data:
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=group_id)) group: Group = group_db.where_one(
Group(), "group_id = ?", group_id, default=Group(group_id=group_id)
)
__group_data[str(group_id)] = group __group_data[str(group_id)] = group
session = __group_data[group_id] session = __group_data[group_id]
else: else:
# session: User = user_db.first(User(), "user_id = ?", event.user_id, default=User(user_id=str(event.user_id))) # session: User = user_db.first(User(), "user_id = ?", event.user_id, default=User(user_id=str(event.user_id)))
user_id = str(event.user.id if isinstance(event, satori.event.Event) else event.user_id) user_id = str(
event.user.id if isinstance(event, satori.event.Event) else event.user_id
)
if user_id not in __user_data: if user_id not in __user_data:
user: User = user_db.where_one(User(), "user_id = ?", user_id, default=User(user_id=user_id)) user: User = user_db.where_one(
User(), "user_id = ?", user_id, default=User(user_id=user_id)
)
__user_data[user_id] = user __user_data[user_id] = user
session = __user_data[user_id] session = __user_data[user_id]
# 默认停用插件在启用列表内表示启用 # 默认停用插件在启用列表内表示启用
@ -141,12 +164,19 @@ def set_plugin_session_enable(event: T_MessageEvent, plugin_name: str, enable: b
""" """
if event_utils.get_message_type(event) == "group": if event_utils.get_message_type(event) == "group":
session: Group = group_db.where_one(Group(), "group_id = ?", str(event_utils.get_group_id(event)), session: Group = group_db.where_one(
default=Group(group_id=str(event_utils.get_group_id(event)))) Group(),
"group_id = ?",
str(event_utils.get_group_id(event)),
default=Group(group_id=str(event_utils.get_group_id(event))),
)
else: else:
session: User = user_db.where_one(User(), "user_id = ?", str(event_utils.get_user_id(event)), session: User = user_db.where_one(
default=User(user_id=str(event_utils.get_user_id(event)))) User(),
print(session) "user_id = ?",
str(event_utils.get_user_id(event)),
default=User(user_id=str(event_utils.get_user_id(event))),
)
default_enable = get_plugin_default_enable(plugin_name) default_enable = get_plugin_default_enable(plugin_name)
if default_enable: if default_enable:
if enable: if enable:
@ -181,7 +211,8 @@ def get_plugin_global_enable(plugin_name: str) -> bool:
GlobalPlugin(), GlobalPlugin(),
"module_name = ?", "module_name = ?",
plugin_name, plugin_name,
default=GlobalPlugin(module_name=plugin_name, enabled=True)) default=GlobalPlugin(module_name=plugin_name, enabled=True),
)
__global_enable[plugin_name] = plugin.enabled __global_enable[plugin_name] = plugin.enabled
return __global_enable[plugin_name] return __global_enable[plugin_name]
@ -201,7 +232,8 @@ def set_plugin_global_enable(plugin_name: str, enable: bool):
GlobalPlugin(), GlobalPlugin(),
"module_name = ?", "module_name = ?",
plugin_name, plugin_name,
default=GlobalPlugin(module_name=plugin_name, enabled=True)) default=GlobalPlugin(module_name=plugin_name, enabled=True),
)
plugin.enabled = enable plugin.enabled = enable
plugin_db.save(plugin) plugin_db.save(plugin)
@ -219,7 +251,9 @@ def get_plugin_can_be_toggle(plugin_name: str) -> bool:
bool: 插件是否可以被启用/停用 bool: 插件是否可以被启用/停用
""" """
plug = nonebot.plugin.get_plugin(plugin_name) plug = nonebot.plugin.get_plugin(plugin_name)
return plug.metadata.extra.get("toggleable", True) if plug and plug.metadata else True return (
plug.metadata.extra.get("toggleable", True) if plug and plug.metadata else True
)
def get_group_enable(group_id: str) -> bool: def get_group_enable(group_id: str) -> bool:
@ -234,7 +268,9 @@ def get_group_enable(group_id: str) -> bool:
""" """
group_id = str(group_id) group_id = str(group_id)
if group_id not in __group_data: if group_id not in __group_data:
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=group_id)) group: Group = group_db.where_one(
Group(), "group_id = ?", group_id, default=Group(group_id=group_id)
)
__group_data[group_id] = group __group_data[group_id] = group
return __group_data[group_id].enable return __group_data[group_id].enable
@ -249,7 +285,9 @@ def set_group_enable(group_id: str, enable: bool):
enable (bool): 是否启用 enable (bool): 是否启用
""" """
group_id = str(group_id) group_id = str(group_id)
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=group_id)) group: Group = group_db.where_one(
Group(), "group_id = ?", group_id, default=Group(group_id=group_id)
)
group.enable = enable group.enable = enable
__group_data[group_id] = group __group_data[group_id] = group

Some files were not shown because too many files have changed in this diff Show More