✔❤大更新!

This commit is contained in:
EillesWan 2024-07-18 03:22:33 +08:00
parent 93ced26e07
commit 1116d033d0
35 changed files with 953 additions and 443 deletions

View File

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
.venv/
.idea/
.vscode/
.pycharm/
.cache/
node_modules/
data/

123
LICENSE.MD Normal file
View File

@ -0,0 +1,123 @@
# 汉钰律许可协议
**总第一版 · 二〇二四年七月七日编**
## 一、重要须知
1. 为保护采用本协议的作品在开源过程中,其著作权人所应有的权益,根据**中华人民共和国著作权法和相关法律法规**,制定本协议。
2. 本协议履行过程中,请注意本协议中**免除或限制**民事主体**责任或权利**的条款、法律适用和争议解决条款(尤其是加有特殊标记的条款),这些条款应在中国法律所允许的范围内最大程度地适用。
3. 若本协议所涉及的自然人**未满 18 周岁**,该自然人应在监护人的陪同下阅读本协议及有关本协议的条款内容,并在取得其监护人同意后开始或继续应用本协议所授权的行为。
4. 由于互联网服务、互联网内容的特殊性,若本协议以电子协议形式分发并签订,其依然有效。您一旦开始对本协议所授权之作品进行本协议所授权的行为,即视为您已经阅读、理解并同意并已经接受本协议的全部条款。
5. 本协议的订立、履行、解释及争议的解决均**适用中华人民共和国法律并排除其他一切冲突法的适用**。_本协议订立于许可证最初的颁发者的地址。若其为自然人则订立于该自然人户籍所在地若为法人或非法人组织则订立于其注册地_。本协议的订立各方应友好协商解决于协议所规定之行为的履行相关的争议如协商不成任何一方均可向合同签订地有管辖权的人民法院提起诉讼。
6. 本协议的原本仅为现代汉语,书写于简体中文。若存在其他语言的翻译或其他同等语言但非简体中文文本的版本,应当无法律效力。
## 二、术语定义
1. “**许可证**”、“**协议**”(后文称“本协议”)是指根据本文档中所列举的全部术语、定义、条款、限制等文本,是本合同的简称称谓。本合同全称是“汉钰律许可协议”。
2. “**协议颁发者**”(后文称“颁发者”)是将条款或协议应用于其拥有著作财产权的作品的民事主体,或由其指定从而拥有颁发者身份的民事主体。
3. “**源**”形式是指对包括但不限于 软件、硬件、文档、配置项 等种类的作品进行修改、编辑的首选形式;若不存在首选形式,则初次编辑该作品所需的形式即为源形式。
4. “**目标**”形式是指对源形式进行机械转换、翻译、打印、制造、加工等同类型活动后形成的结果形式,包括但不限于源代码编译后的目标软件、生成的文件、转换出的媒体、制造出的机械、打印出的实体文本、加工后的零件。
5. “**采用本协议的作品**”(后文称“此作品”)是指经颁发者授权而使用本协议进行授权的任何作品,该作品应在自然人可见处明确附加一个自然人可读的版权通知(可以参考文末附录中提供的示例);若在一个可分割的作品中,部分地采用本协议进行授权,则该部分应当视为一个独立的采用本协议的作品,该作品应当在自然人可见处明确附加一个自然人可读的范围限定和版权通知(同样可以参考文末附录中提供的示例)。
6. “**贡献**”是指对作品进行的,意在提交给此作品颁发者以让著作权人包含在其作品中的任何修订或补充,该修订或补充同样属于一种作品。依据此定义,“提交”一词表示经由此作品颁发者所指定的形式,将其所进行的修改发送给此作品颁发者。该形式应当包括在此作品颁发者指定的平台内发送易于编辑的修改信息、在此作品颁发者指定的电子邮箱中发送易于编辑的修改信息、在此作品颁发者指定的源码控制系统或发布跟踪系统上提交的易于编辑的修改信息,但由著作权人以明显标注或指定为“非贡献”的活动除外。颁发者自己对作品进行的修改同样视作对作品的贡献。
7. “**贡献者**”是指此作品颁发者接受的贡献的提交者,或包含在作品的贡献清单中的民事主体。贡献者在提交贡献并经此作品颁发者通过且该贡献已经被应用于此作品中后,该贡献者应当视为此作品的著作权人之一,但不应视为此作品非其贡献的部分的著作权人。一个作品的颁发者同样属于其贡献者。**请注意**,针对贡献者提交的贡献,该贡献者应被视为该贡献的协议颁发者,但不应视作本作品的颁发者。
8. “**用户**”、“**使用者**”是指行使本协议所授权之行为的民事主体。据此,贡献者亦属于用户。
9. “**商业性使用**”、“**商用**”是指任何以谋取利益为目的的使用,包括但不限于以贩卖、出租的形式对作品进行使用;但若将该牟利活动明确指示为“捐赠”,且在牟利者进行本协议所授权的活动时不以捐赠数额为标准,则此种的获取利益的“捐赠”行为不属于商业性使用。
## 三、权利授予
1. 任何由颁发者所进行的特殊声明、特别注意等此类内容,应当在法律效力上高于本协议的条款或声明;这些声明若与本协议冲突,本协议的该冲突部分无效;本协议与这些声明共同构成颁发者与用户之间的合同。
2. 此作品的贡献者享有其贡献的完整著作权。
3. 此作品的贡献者将自己的贡献的全部著作财产权,免费、公开、不可撤销、无限期、非专有地授予此作品的全部著作权人,并准许其在全世界范围内使用上述权利;若无明确的标识,贡献者允许此作品的颁发者对其贡献进行免费、公开、不可撤销、无限期、非专有、世界范围内的商业性使用。
4. 此作品的著作权人及贡献者授予用户**免费、公开、不可撤销、非专有、非商用**地以任意形式**复制、发行、展览、表演、放映、广播、信息网络传播、摄制、改编、翻译、汇编、二次授权**的权利,准许其在此作品颁发者所指定的区域与时间内行使上述权利;若此作品颁发者未特别指定的,则视作在全世界范围内无限期地授权;若此作品颁发者特别指定在特定情况下可以商用,则应当按照其所指定的条件进行商业性使用,商用的过程中,应当明确标识此作品的著作权人。
5. 一旦此作品有任意由非贡献形式而产生的更改,更改的部分将不视为此作品的一部分,除非该部分不可离开此作品单独存在;若该部分必须依赖此作品而不可与此作品分离从而单独存在,则更改后的作品不视作此作品,在这种情况下,除非此更改后的作品已获得此作品颁发者的特殊许可、或更改者即为此作品颁发者本人,否则对该作品进行的任何活动都应当遵守本协议。
6. 经贡献而产生的对此作品的更改,属于此作品的一部分;在此情况下,更改后的作品,依旧视作此作品。
7. 依据本款的第 4 条,若用户在本协议的授权下,将此作品授予他人进行任何形式的活动(即“二次授权”、“二次分发”),则应确保其使用的协议或授权内容,与本协议的条款不冲突;当存在与本协议条款的冲突时,则该冲突内容无效,被授权的第三方应依照本协议的条款进行活动;除非该用户获得了此作品颁发者的特殊许可、或该用户即为此作品颁发者本人。
8. 依据本款的第 5 条,若由非贡献形式而产生更改的部分是可分割而不需依赖此作品即可单独存在的,若该部分明确注明不使用本协议进行授权或明确声明了其他授权条款,则该部分不视作采用本协议;但未更改的部分仍应视作原此作品的一部分,需要采用本协议进行授权,除非此更改后的作品已获得此作品颁发者的特殊许可、或更改者即为此作品颁发者本人。
9. 若此作品或所提交的贡献包含其著作权人的专利,则该专利所有人即此作品的著作权人应准许此作品全体著作权人**免费、公开、不可撤销、非专有、无版权费的专利许可**,以便贡献者对作品进行本协议所授权进行的活动。
10. 上述专利许可的授予,仅适用于在所提交的贡献中,可由专利所有者授予的,且在对此作品进行本协议所授权的活动中,必须使用的专利。
11. 如果用户对任何民事主体,因其在进行本协议所授权进行的活动中侵犯该用户的专利而提起诉讼,那么根据本协议授予该用户的所有关于此作品的任何其他专利许可将在提起上述诉讼之日起终止。
12. 如果本作品作为用户的其他作品的不可分割的一部分进行任何民事活动,本协议依旧对本作品(即该用户的其他作品的一部分)生效;若本作品完全融入该用户的其他作品之中而不可独立存在,则该用户需要保证其作品存在与本协议冲突的条款;除非该作品已获得此作品颁发者的特殊许可、或该用户即为此作品颁发者本人。
## 四、使用条件
在对此作品进行本协议所授权的民事活动中,应当同时满足以下条款:
1. 用户必须为此作品的任何其他接收者提供本协议的副本,在不得已无法提供副本的情况下,也应明确指示其他接收者可查阅本协议的位置。
2. 用户必须在修改后的作品中附带明显的通知,声明用户已更改文件,并注明更改位置。
3. 若用户二次分发此作品,可以选择向此作品的接收者提供无偿或有偿的担保维修、支持服务或其他责任、义务。但是,该用户只可以其自己的名义提供上述内容,不得以任何其他贡献者的名义。且该用户必须明确表明任何此类责任或义务是由其个人独立提供,且其同意并应当承担赔偿此作品的全体贡献者因其个人承担上述责任义务而产生的任何赔偿责任。
4. 用户不得删除或更改此作品中包含的任何许可声明(包括版权声明,专利声明,免责声明,或赔偿责任限制),除非该更改是对已知事实错误的修补、或其已获得此作品颁发者的特殊许可、或更改者即为此作品颁发者本人。
5. 若此作品将权益的声明通知作为一部分,那么由用户分发的任何版本的作品中须至少在下列三处之一包含该声明通知的自然人可读副本:
- 该作品的权益声明通知中
- 在源形式的文件中(当且仅当该作品开放源代码)
- 在惯例中作为第三方通知出现之处(当且仅当该作品会产生画面,且该画面可被自然人详细观察)
该通知的内容仅供信息提供,不应对许可证进行任何文字上的修改。用户可在其分发的作品中,在不构成修改本协议的前提下,在作品自身的声明通知或属性描述后或作为附录添加。
6. 依据本款第3条若用户二次分发此作品时选择向作品的接收者提供收费的担保服务则必须明确告知该接收者本协议全部内容与此作品原出处并确保其知悉上述内容但若用户在二次分发此作品是不选择提供任何服务则该用户不允许向作品的接收者收取任何费用除非该用户获得了此作品颁发者的特殊许可、或该用户即为此作品颁发者本人。
## 五、提交贡献
除非贡献者明确声明,在本作品中由该贡献者向颁发者的提供的提交,必须符合本协议的条款,并与本协议的条款不存在冲突;除非此贡献中与本协议冲突的附加条款已获得颁发者的特殊许可、或贡献者即为此作品颁发者本人。
## 六、商标相关
本协议并未授予用户,将颁发者的商标、专属标记或特定产品名称,用于合理的或惯例性的描述或此类声明之外其他任何位置的权利。
## 七、免责声明
1. 若非因法律要求或经过了特殊准许,此作品在根据本协议“原样”提供的基础上,**不予提供任何形式的担保、任何明示、任何暗示或类似承诺**,此类包括但不限于担保此作品毫无缺陷、担保此作品适于贩卖、担保此作品适于特定目的、担保使用此作品绝不侵权。用户将自行承担因此作品的质量或性能问题而产生的全部风险。若此作品在任何方面欠妥,将由用户(而非任何贡献者、而非任何颁发者)承担所有必要的服务、维修或除错的任何成本。本免责声明本许可的重要组成部分。当且仅当遵守本免责声明时,本协议的其他条款中对本作品的使用授权方可生效。
2. 无论是因何种原因,如果不是在法律规定的特殊情况(如,确为贡献者的故意或重大过失)下或者经过了特殊准许,即使贡献者事先已知发生损害的可能,在使用本作品时,用户产生的任何直接、间接、特殊、偶然或必然造成的损失(包括但不限于商誉损失、工作延误、计算机系统故障等),**均不由任一贡献者承担**。
**以上是本许可协议的全部条款**
---
附录
**如何在自己的作品中应用 汉钰律许可协议**
若要在自己源形式的作品应用本协议,请在其中附加下面的通知模板,并将六角括号“〔〕”中的字段替换成自身的实际信息来替换(不包括括号本身)。这些文本必须以对应文件格式适当的注释句法包含在其中,可以是实体的纸质文档、也可以是网络公告或者计算机文件;或者脱离该源之外,另起一个新的文件,使之指向要应用本协议的那个作品。同时也建议将作品名或类别名以及目的说明之类的声明囊括在同一个可被打印的页面上作为版权通知的整体,这样更加容易的区分出第三方内容。
若需要在自己以目标形式存在的作品中应用本协议,同样需要附加下面的通知模板并更改六角括号中的字样。但是,这些文本可以是位于作品的标签上、位于作品的用户可见且能被自然人详细观察的画面之中、或者按照惯例中许可协议应该出现的位置;同时,这些文本的所处位置应当能够明确指示到本协议应用的那个作品。另外,建议将作品名或类别名以及目的说明之类的声明囊括在同一个可被打印的位置上作为版权通知的整体,这样更加容易的区分出第三方内容。
**通知模板**
```
版权所有 © 〔年份〕 〔著作权人〕
〔或者:版权所有 (C) 〔年份〕 〔著作权人〕〕
〔该作品〕根据 第一版 汉钰律许可协议(“本协议”)授权。
任何人皆可从以下地址获得本协议副本:〔本协议副本所在地址〕。
若非因法律要求或经过了特殊准许,此作品在根据本协议“原样”提供的基础上,不予提供任何形式的担保、任何明示、任何暗示或类似承诺。也就是说,用户将自行承担因此作品的质量或性能问题而产生的全部风险。
详细的准许和限制条款请见原协议文本。
```

View File

@ -1,31 +1,31 @@
LSO license
LiteyukiStudio Opensource license
---
Copyright © 2024 Snowykami
---
Free to grant the same license-based rights to any person or organization who obtains a copy
including but not limited to using, copying, modifying, merging, publishing, distributing, sublicenseing, and/or selling copies of the software
This software and related documentation files (hereinafter referred to as "this software") are licensed in the same way as the base, and are released in the form of open source on the Internet or other media platforms
Everyone has the right to obtain a copy and obtain permission to distribute and/or use it in the above manner
However, when obtaining a copy, it is still necessary to pay attention to the following:
- The above copyright notice and this permission notice shall be included in a copy of the Software
- When using this software and its copies, it is still necessary to maintain the same form as the original
- When using this software, you still need to disclose the copy of this software under the same license:
- Do not profit from copies of this software in a non-original license without the permission of the original author
---
The software is provided as a "copy as is" without any warranty of any kind, either express or implied:
including but not limited to the warranty of merchantability, non-infringement for specific purposes
In any case, the author or copyright owner shall not be liable for any claims, damages, or other liabilities arising from the use of the software by the author or copyright owner, whether in contract litigation, infringement litigation, or other litigation. The author and its copyright owner have the right to refuse compensation for any losses caused by the user for personal reasons
LSO license
LiteyukiStudio Opensource license
---
Copyright © 2024 Snowykami
---
Free to grant the same license-based rights to any person or organization who obtains a copy
including but not limited to using, copying, modifying, merging, publishing, distributing, sublicenseing, and/or selling copies of the software
This software and related documentation files (hereinafter referred to as "this software") are licensed in the same way as the base, and are released in the form of open source on the Internet or other media platforms
Everyone has the right to obtain a copy and obtain permission to distribute and/or use it in the above manner
However, when obtaining a copy, it is still necessary to pay attention to the following:
- The above copyright notice and this permission notice shall be included in a copy of the Software
- When using this software and its copies, it is still necessary to maintain the same form as the original
- When using this software, you still need to disclose the copy of this software under the same license:
- Do not profit from copies of this software in a non-original license without the permission of the original author
---
The software is provided as a "copy as is" without any warranty of any kind, either express or implied:
including but not limited to the warranty of merchantability, non-infringement for specific purposes
In any case, the author or copyright owner shall not be liable for any claims, damages, or other liabilities arising from the use of the software by the author or copyright owner, whether in contract litigation, infringement litigation, or other litigation. The author and its copyright owner have the right to refuse compensation for any losses caused by the user for personal reasons

View File

@ -1,31 +1,31 @@
LSO license
LiteyukiStudio Opensource license
---
版权所有 © 2024 Snowykami
---
免费向任何获得副本的人或组织授予以相同许可为基础的权利
包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件的副本
本软件及相关文档文件(以下简称"本软件")在相同方式许可为基础, 以开源的形式发布于互联网抑或其他媒体介质平台
任何人都有权利获取副本并以上述方式获取许可传播和/或使用
但获取副本时仍需注意:
- 上述版权声明和本许可声明应包含在本软件的副本中
- 使用本软件及其副本时仍需保持与原有形式相同
- 在使用时仍需将本软件的副本以相同许可公开表现:
- 不得未经原作者允许将本软件的副本以非原许可的形式对外盈利
---
该软件按"原样"之副本提供,不提供任何形式的任意保证,明示或暗示:
包括但不限于适销性保证, 适用于特定目的非侵权
在任何情况下, 作者或版权所有者对任何非因作者或版权所有者使用该软件造成的索赔、损害或其他责任, 无论是在合同诉讼、侵权行为还是其他诉讼中都不具有责任, 作者及其版权所有者有权利驳回使用者因个人原因造成的任何损失之赔付
LSO license
LiteyukiStudio Opensource license
---
版权所有 © 2024 Snowykami
---
免费向任何获得副本的人或组织授予以相同许可为基础的权利
包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件的副本
本软件及相关文档文件(以下简称"本软件")在相同方式许可为基础, 以开源的形式发布于互联网抑或其他媒体介质平台
任何人都有权利获取副本并以上述方式获取许可传播和/或使用
但获取副本时仍需注意:
- 上述版权声明和本许可声明应包含在本软件的副本中
- 使用本软件及其副本时仍需保持与原有形式相同
- 在使用时仍需将本软件的副本以相同许可公开表现:
- 不得未经原作者允许将本软件的副本以非原许可的形式对外盈利
---
该软件按"原样"之副本提供,不提供任何形式的任意保证,明示或暗示:
包括但不限于适销性保证, 适用于特定目的非侵权
在任何情况下, 作者或版权所有者对任何非因作者或版权所有者使用该软件造成的索赔、损害或其他责任, 无论是在合同诉讼、侵权行为还是其他诉讼中都不具有责任, 作者及其版权所有者有权利驳回使用者因个人原因造成的任何损失之赔付

View File

@ -1,8 +1,10 @@
<div align="center">
[//]: # (<img src="https://cdn.liteyuki.icu/static/svg/lylogo-full.svg" style="align-content: center; width: 50%; margin-top:10%;" alt="a">)
[//]: # '<img src="https://cdn.liteyuki.icu/static/svg/lylogo-full.svg" style="align-content: center; width: 50%; margin-top:10%;" alt="a">'
[![][banner]][lightyuki-link]
<h2><a href="https://bot.liteyuki.icu"> <span style="color: #a2d8f4">轻雪</span> <span style="color: #d0e9ff">6</span></a></h2>
<h2>>尹灵温<<a href="https://bot.liteyuki.icu"> <span style="color: #a2d8f4">轻雪</span> <span style="color: #d0e9ff">6</span></a></h2>
<h4> <span style="color: #a2d8f4">✨ 轻量,高效,易于扩展✨</span></h4>
[![][OneBot]][onebot-link]
@ -14,39 +16,45 @@
- 基于[Nonebot2](https://github.com/nonebot/nonebot2),有良好的生态支持
- 开箱即用,无需复杂配置
- 集成包管理器,支持一键安装插件
- 支持OneBot标准通信但不限于此
- 支持 OneBot 标准通信但不限于此
- 自定义主题支持,满足审美需求
- 国际化支持,支持多语言
- 高性能500插件2s内启动
- 国际化支持,支持多语言本地化
- 高性能500 插件 10s 内启动
<h3>👇更多内容请访问👇</h3>
<h2><a href="https://bot.liteyuki.icu">轻雪机器人主页</a></h2>
</div>
### 感谢
- [NoneBot2](https://nonebot.dev)提供的框架支持
- [nonebot-plugin-htmlrender](https://github.com/kexue-z/nonebot-plugin-htmlrender)提供的渲染功能
- [nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna)提供的命令解析功能
- 感谢[NoneBot2](https://nonebot.dev)提供的框架支持
- 感谢[nonebot-plugin-htmlrender](https://github.com/kexue-z/nonebot-plugin-htmlrender)提供的渲染功能
- 感谢[nonebot-plugin-alconna](https://github.com/ArcletProject/nonebot-plugin-alconna)提供的命令解析功能
- 十分感谢[神羽SnowyKami](https://github.com/snowykami)提供的技术指导和服务器资源
- 特别感谢[云裳工作室](https://doc.ysmcc.cn/doc/1/)提供的服务器挂载
- 由衷的感谢我在学习生活中遇到的所有朋友们,你们身为我生命中的一处景色,不断地推进我此生的进程。
### 许可证
本特定版本的 轻雪机器人 以 汉玉律许可协议 授权开源\
兼容并继承自LSO license (LiteyukiStudio Opensource license)
版权所有 © 2024 SnowyKami & EillesWan
轻雪机器人睿乐定制版(LiteyukiBot-TriM)根据 第一版 汉钰律许可协议(“本协议”)授权。\
任何人皆可从以下地址获得本协议副本:[汉钰律许可协议 第一版](https://gitee.com/EillesWan/YulvLicenses/raw/master/%E6%B1%89%E9%92%B0%E5%BE%8B%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE/%E6%B1%89%E9%92%B0%E5%BE%8B%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE.MD)。\
若非因法律要求或经过了特殊准许,此作品在根据本协议“原样”提供的基础上,不予提供任何形式的担保、任何明示、任何暗示或类似承诺。也就是说,用户将自行承担因此作品的质量或性能问题而产生的全部风险。\
详细的准许和限制条款请见原协议文本。
[OneBot]: https://img.shields.io/badge/OneBot-11/12-blue?style=for-the-badge
[NoneBot2]: https://img.shields.io/badge/Nonebot-2-red?style=for-the-badge
[Liteyuki6.0]: https://img.shields.io/badge/Liteyuki-6.0-blue?style=for-the-badge
[Python3.10+]: https://img.shields.io/badge/Python-3.10+-blue?style=for-the-badge
[Usage]: https://img.shields.io/badge/文档-页面-blue?style=for-the-badge
[onebot-link]:https://onebot.dev/
[nonebot-link]:https://nonebot.dev/
[lightyuki-link]:/
[python-link]:https://www.python.org/
[usage-link]:https://bot.liteyuki.icu/
[banner]: https://socialify.git.ci/LiteyukiStudio/LiteyukiBot/image?description=1&forks=1&issues=1&Plus&pulls=1&stargazers=1&theme=Auto&logo=https%3a%2f%2fcdn.liteyuki.icu%2fstatic%2fsvg%2flylogo-full.svg
[onebot-link]: https://onebot.dev/
[nonebot-link]: https://nonebot.dev/
[lightyuki-link]: /
[python-link]: https://www.python.org/
[usage-link]: https://bot.liteyuki.icu/
[banner]: https://socialify.git.ci/TriM-Organization/LiteyukiBot-TriM/image?description=1&forks=1&issues=1&Plus&pulls=1&stargazers=1&theme=Auto&logo=https://gitee.com/TriM-Organization/Linglun-Converter/raw/master/resources/TriMO_LOGO.png

View File

@ -1,10 +0,0 @@
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free

View File

@ -27,4 +27,6 @@ pillow~=10.2.0
jieba~=0.42.1
pip~=23.2.1
fastapi~=0.110.0
python-dotenv~=1.0.1
python-dotenv~=1.0.1
pypinyin
zhDateTime>=1.0.3

View File

@ -4,8 +4,8 @@ from git import Repo
from src.utils.base.config import get_config
remote_urls = [
"https://github.com/LiteyukiStudio/LiteyukiBot.git",
"https://gitee.com/snowykami/LiteyukiBot.git"
"https://github.com/TriM-Organization/LiteyukiBot-TriM.git",
"https://github.com/TriM-Organization/LiteyukiBot-TriM.git"
]

View File

@ -31,6 +31,20 @@ driver = get_driver()
markdown_image = common_db.where_one(StoredConfig(), default=StoredConfig()).config.get("markdown_image", False)
@on_alconna(
command=Alconna(
"ryounecho",
Args["text", str, ""],
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(bot: T_Bot, matcher: Matcher, result: Arparma):
if result.main_args.get("text"):
await matcher.finish(Message(unescape(result.main_args.get("text"))))
else:
await matcher.finish(f"君安!灵温向你问好~\n此机 {bot.self_id}")
@on_alconna(
command=Alconna(
"liteecho",
@ -43,13 +57,13 @@ async def _(bot: T_Bot, matcher: Matcher, result: Arparma):
if result.main_args.get("text"):
await matcher.finish(Message(unescape(result.main_args.get("text"))))
else:
await matcher.finish(f"Hello, Liteyuki!\nBot {bot.self_id}")
await matcher.finish(f"Hello! TriM-Liteyuki!\nRyBot {bot.self_id}")
@on_alconna(
aliases={"更新轻雪"},
aliases={"更新灵温"},
command=Alconna(
"update-liteyuki"
"update-ryoun"
),
permission=SUPERUSER
).handle()
@ -59,7 +73,7 @@ async def _(bot: T_Bot, event: T_MessageEvent):
ulang = get_user_lang(str(event.user.id if isinstance(event, satori.event.Event) else event.user_id))
success, logs = update_liteyuki()
reply = "Liteyuki updated!\n"
reply = "尹灵温 更新完成!\n"
reply += f"```\n{logs}\n```\n"
btn_restart = md.btn_cmd(ulang.get("liteyuki.restart_now"), "reload-liteyuki")
pip.main(["install", "-r", "requirements.txt"])
@ -68,15 +82,15 @@ async def _(bot: T_Bot, event: T_MessageEvent):
@on_alconna(
aliases={"重启轻雪"},
aliases={"重启灵温","重启尹灵温", "重载灵温"},
command=Alconna(
"reload-liteyuki"
"reload-ryoun",
),
permission=SUPERUSER
).handle()
# Satori OK
async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
await matcher.send("Liteyuki reloading")
await matcher.send("尹灵温 正在重载")
temp_data = common_db.where_one(TempConfig(), default=TempConfig())
temp_data.data.update(
@ -179,15 +193,15 @@ async def _(event: T_MessageEvent, matcher: Matcher):
ulang.get("liteyuki.image_mode_on" if stored_config.config["markdown_image"] else "liteyuki.image_mode_off"))
@on_alconna(
command=Alconna(
"liteyuki-docs",
),
aliases={"轻雪文档"},
).handle()
# Satori OK
async def _(matcher: Matcher):
await matcher.finish("https://bot.liteyuki.icu/usage")
# @on_alconna(
# command=Alconna(
# "liteyuki-docs",
# ),
# aliases={"轻雪文档"},
# ).handle()
# # Satori OK
# async def _(matcher: Matcher):
# await matcher.finish("https://bot.liteyuki.icu/usage")
@on_alconna(
@ -350,7 +364,7 @@ async def _(bot: T_Bot):
if isinstance(bot, satori.Bot):
await bot.send_message(
channel_id=reload_session_id,
message="Liteyuki reloaded in %.2f s" % delta_time
message="灵温 重载耗时 %.2f" % delta_time
)
else:
await bot.call_api(
@ -358,7 +372,7 @@ async def _(bot: T_Bot):
message_type=reload_session_type,
user_id=reload_session_id,
group_id=reload_session_id,
message="Liteyuki reloaded in %.2f s" % delta_time
message="灵温 重载耗时 %.2f" % delta_time
)
@ -369,8 +383,8 @@ async def every_day_update():
result, logs = update_liteyuki()
pip.main(["install", "-r", "requirements.txt"])
if result:
await broadcast_to_superusers(f"Liteyuki updated: ```\n{logs}\n```")
nonebot.logger.info(f"Liteyuki updated: {logs}")
await broadcast_to_superusers(f"灵温已更新: ```\n{logs}\n```")
nonebot.logger.info(f"灵温已更新: {logs}")
Reloader.reload(5)
else:
nonebot.logger.info(logs)

View File

@ -8,22 +8,22 @@ __plugin_meta__ = PluginMetadata(
name="统计信息",
description="统计机器人的信息,包括消息、群聊等,支持排名、图表等功能",
usage=(
"```\nstatistic message 查看统计消息\n"
"可选参数:\n"
" -g|--group [group_id] 指定群聊\n"
" -u|--user [user_id] 指定用户\n"
" -d|--duration [duration] 指定时长\n"
" -p|--period [period] 指定次数统计周期\n"
" -b|--bot [bot_id] 指定机器人\n"
"命令别名:\n"
" statistic|stat message|msg|m\n"
"```"
"```\nstatistic message 查看统计消息\n"
"可选参数:\n"
" -g|--group [group_id] 指定群聊\n"
" -u|--user [user_id] 指定用户\n"
" -d|--duration [duration] 指定时长\n"
" -p|--period [period] 指定次数统计周期\n"
" -b|--bot [bot_id] 指定机器人\n"
"命令别名:\n"
" statistic|stat message|msg|m\n"
"```"
),
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki" : True,
"toggleable" : False,
"default_enable": True,
}
"liteyuki": True,
"toggleable": False,
"default_enable": True,
},
)

View File

@ -93,6 +93,7 @@ async def generate_status_card(
hardware: dict,
liteyuki: dict,
lang="zh-CN",
motto={"text":"风朗气清","source":"成语一则"},
bot_id="0",
) -> bytes:
return await template2image(
@ -103,6 +104,7 @@ async def generate_status_card(
"hardware": hardware,
"liteyuki": liteyuki,
"localization": get_local_data(lang),
"motto": motto,
}
},
)

View File

@ -1,15 +1,33 @@
import zhDateTime
import requests
import random
from src.utils import event as event_utils
from src.utils.base.language import get_user_lang
from src.utils.base.language import get_user_lang, get_default_lang_code, Language
from src.utils.base.ly_typing import T_Bot, T_MessageEvent
from .api import *
require("nonebot_plugin_alconna")
from nonebot_plugin_alconna import on_alconna, Alconna, Subcommand, UniMessage
from nonebot_plugin_alconna import (
on_alconna,
Alconna,
Subcommand,
UniMessage,
Option,
store_true,
AlconnaQuery,
Query,
Arparma,
)
require("nonebot_plugin_apscheduler")
from nonebot_plugin_apscheduler import scheduler
status_alc = on_alconna(
aliases={"状态"},
command=Alconna(
"status",
Option("-r|--refresh", alias={"refr", "r", "刷新"}, action=store_true),
Subcommand(
"memory",
alias={"mem", "m", "内存"},
@ -18,23 +36,95 @@ status_alc = on_alconna(
"process",
alias={"proc", "p", "进程"},
),
Subcommand(
"refresh",
alias={"refr", "r", "刷新"},
),
# Subcommand(
# "refresh",
# alias={"refr", "r", "刷新"},
# ),
),
)
yanlun = on_alconna(
aliases={"yanlun", "言·论", "yan_lun"},
command=Alconna(
"言论",
Option(
"-r|--refresh",
default=False,
alias={"刷新", "更新", "update"},
action=store_true,
),
Option("-c|--count", default=False, alias={"统计"}, action=store_true),
),
)
# 每天4点更新
@scheduler.scheduled_job("cron", hour=4)
async def every_day_update():
ulang = Language(get_default_lang_code(), "zh-WY")
nonebot.logger.success(ulang.get("yanlun.refresh.success", COUNT=update_yanlun()))
def update_yanlun():
global yanlun_texts
solar_datetime = zhDateTime.DateTime.now()
lunar_datetime = solar_datetime.to_lunar()
solar_date = (solar_datetime.month, solar_datetime.day)
lunar_date = (lunar_datetime.lunar_month, lunar_datetime.lunar_day)
if solar_date == (4, 3):
yanlun_texts = ["金羿ELS 生日快乐~"]
elif solar_date == (8, 6):
yanlun_texts = ["诸葛八卦 生日快乐~"]
else:
try:
yanlun_texts = (
requests.get(
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt",
)
.text.strip("\n")
.split("\n")
)
except (ConnectionError, requests.HTTPError, requests.RequestException) as E:
nonebot.logger.warning(f"读取言·论信息发生 互联网连接 错误:\n{E}")
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException
except BaseException as E:
nonebot.logger.warning(f"读取言·论信息发生 未知 错误:\n{E}")
yanlun_texts = ["灵光焕发 深艺献心"]
return len(yanlun_texts)
update_yanlun()
def random_yanlun() -> tuple:
seq = random.choice(yanlun_texts).replace(" ", "\t").split("\t——", 1)
return seq[0], "" if len(seq) == 1 else seq[1]
status_card_cache = {} # lang -> bytes
@status_alc.handle()
async def _(event: T_MessageEvent, bot: T_Bot):
ulang = get_user_lang(event_utils.get_user_id(event))
async def _(
result: Arparma,
event: T_MessageEvent,
bot: T_Bot,
# refresh: Query[bool] = AlconnaQuery("refresh.value", False),
):
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
global status_card_cache
if ulang.lang_code not in status_card_cache.keys() or (
ulang.lang_code in status_card_cache.keys()
and time.time() - status_card_cache[ulang.lang_code][1] > 60
if (
result.options["refresh"].value
or ulang.lang_code not in status_card_cache.keys()
or (
ulang.lang_code in status_card_cache.keys()
and time.time() - status_card_cache[ulang.lang_code][1] > 60
)
):
status_card_cache[ulang.lang_code] = (
await generate_status_card(
@ -42,6 +132,7 @@ async def _(event: T_MessageEvent, bot: T_Bot):
hardware=await get_hardware_data(),
liteyuki=await get_liteyuki_data(),
lang=ulang.lang_code,
motto=dict(zip(["text", "source"], random_yanlun())),
bot_id=bot.self_id,
),
time.time(),
@ -58,3 +149,100 @@ async def _():
@status_alc.assign("process")
async def _():
print("process")
@yanlun.handle()
async def _(
result: Arparma,
event: T_MessageEvent,
bot: T_Bot,
# refresh: Query[bool] = AlconnaQuery("refresh.value", False),
# count: Query[bool] = AlconnaQuery("count.value", False),
):
# print(result.options)
if result.options["refresh"].value:
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
global yanlun_texts
try:
yanlun_texts = (
requests.get(
"https://gitee.com/TriM-Organization/LinglunStudio/raw/master/resources/myWords.txt",
)
.text.strip("\n")
.split("\n")
)
await yanlun.send(
UniMessage.text(
ulang.get("yanlun.refresh.success", COUNT=len(yanlun_texts))
)
)
except (ConnectionError, requests.HTTPError, requests.RequestException) as E:
await yanlun.send(
UniMessage.text(
ulang.get(
"yanlun.refresh.failed",
ERR=ulang.get("yanlun.errtype.net"),
ERRCODE=f"\n{E}",
)
)
)
yanlun_texts = ["以梦想为驱使 创造属于自己的未来"]
# noinspection PyBroadException
except BaseException as E:
await yanlun.send(
UniMessage.text(
ulang.get(
"yanlun.refresh.failed",
ERR=ulang.get("yanlun.errtype.unknown"),
ERRCODE=f"\n{E}",
)
)
)
yanlun_texts = ["灵光焕发 深艺献心"]
if result.options["count"].value:
ulang = get_user_lang(event_utils.get_user_id(event)) # type: ignore
authors = [
(
("B站")
if ("\t——B站" in i.upper() or " ——B站" in i.upper())
else (
i.split("\t——")[1].replace(" ", "")
if "\t——" in i
else (
i.split(" ——")[1].replace(" ", "")
if " ——" in i
else ("MYH")
)
)
)
for i in yanlun_texts
]
total = len(yanlun_texts)
chart = sorted(
[(i, authors.count(i)) for i in set(authors)],
key=lambda x: x[1],
reverse=True,
)
await yanlun.send(
UniMessage.text(
ulang.get("yanlun.count.head").replace("ttt", "\t")
+ "\n"
+ "".join(
[
(
"{}\t{}({}%)\n".format(
aut, cnt, int(cnt * 10000 / total + 0.5) / 100
)
if cnt * 100 / total >= chart[10][1] * 100 / total
else ""
)
for aut, cnt in chart
]
)
+ ulang.get("yanlun.count.tail", NUM=total)
)
)
await yanlun.finish(UniMessage.text(random.choice(yanlun_texts)))

View File

@ -1,4 +1,12 @@
.sign-chart {
height: 400px;
background-color: rgba(255, 255, 255, 0.7);
}
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -0,0 +1,7 @@
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -51,4 +51,7 @@ function timestampToTime(timestamp) {
let m = date.getMinutes() + ':'
let s = date.getSeconds()
return M + D + h + m + s
}
}
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'

View File

@ -23,3 +23,5 @@ data["ranking"].forEach((item) => {
document.body.appendChild(row)
})
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Liteyuki Stats Message</title>
@ -10,13 +11,15 @@
<body>
<template id="sign-chart-template">
<div class="info-box sign-chart">
</div>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<template id="sign-chart-template">
<div class="info-box sign-chart">
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_msg.js"></script>
<script src="./js/card.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_msg.js"></script>
<script src="./js/card.js"></script>
</body>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Liteyuki Stats Message</title>
@ -15,19 +16,19 @@
margin-bottom: 10px;
padding-right: 10px;
}
.row-name {
font-size: 40px;
align-content: center;
width: 100px;
text-align: left;
}
.row-icon {
border-radius: 50%;
margin-right: auto;
}
.row-count {
align-content: center;
font-size: 40px;
@ -39,16 +40,18 @@
<body>
<template id="row-template">
<div class="row">
<img src="./img/arrow-up.svg" alt="up" class="row-icon">
<div class="row-name"></div>
<div class="row-count"></div>
</div>
</template>
<template id="row-template">
<div class="row">
<img src="./img/arrow-up.svg" alt="up" class="row-icon">
<div class="row-name"></div>
<div class="row-count"></div>
</div>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_rank.js"></script>
<script src="./js/card.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/stat_rank.js"></script>
<script src="./js/card.js"></script>
</body>

View File

@ -156,4 +156,11 @@ status.seconds=秒
status.cores=核心
status.threads=线程
status.process=进程
status.description=轻雪机器人状态面板
status.description=轻雪机器人状态面板
yanlun.refresh.success=言·论 更新成功,共 {COUNT} 条
yanlun.refresh.failed=更新 言·论 信息发生 {ERR} 错误:{ERRCODE}
yanlun.errtype.net=互联网连接
yanlun.errtype.unknown=未知
yanlun.count.head=出处ttt数量(占比)
yanlun.count.tail=...(共 {NUM} 条)

View File

@ -156,4 +156,11 @@ status.seconds=秒
status.cores=轮核
status.threads=程线
status.process=行轨
status.description=轻雪灵机台
status.description=轻雪灵机台
yanlun.refresh.success=言·论 方新,合{COUNT}条
yanlun.refresh.failed=言·论 因{ERR}而无以新:{ERRCODE}
yanlun.errtype.net=遥讯不得
yanlun.errtype.unknown=无名之亏
yanlun.count.head=所缘ttt几何(比率)
yanlun.count.tail=...(合{NUM}条)

View File

@ -125,3 +125,10 @@
text-align: right;
}
#addition-info {
font-size: 36px;
word-wrap: break-word;
color: var(--main-text-color);
text-align: center;
margin: 30px 0 10px 0;
}

View File

@ -3,7 +3,7 @@ body {
background-size: cover;
background-position: center;
color: white;
/ / 上10px左右10px下0px / / margin: 24 px;
/* // 上10px左右10px下0px // margin: 24 px; */
margin: 20px;
}
@ -55,7 +55,8 @@ body {
background-color: white;
}
.bot-name, .bot-tag {
.bot-name,
.bot-tag {
margin-left: 20px;
}
@ -98,4 +99,9 @@ body {
font-size: 30px;
font-style: italic;
color: #ccc;
}
.addition-info {
font-size: 36px;
color: #fff;
}

View File

@ -3,6 +3,7 @@ const bot_data = data['bot']; // 机器人数据
const hardwareData = data['hardware']; // 硬件数据
const liteyukiData = data['liteyuki']; // LiteYuki数据
const localData = data['localization']; // 本地化语言数据
const motto_ = data['motto']; // 言论数据
/**
* 创建CPU/内存/交换饼图
@ -61,10 +62,10 @@ function createPieChartOption(title, data) {
}
function convertSize(size, precision = 2, addUnit = true, suffix = " XiB") {
function convertSize(size, precision = 2, addUnit = true, suffix = " X字节") {
let isNegative = size < 0;
size = Math.abs(size);
let units = ["", "K", "M", "G", "T", "P", "E", "Z"];
let units = ["", "千", "兆", "吉", "太", "拍", "艾", "泽"];
let unit = "";
for (let i = 0; i < units.length; i++) {
@ -254,20 +255,20 @@ function main() {
cpuChart.setOption(createPieChartOption(`${localData['cpu']}\n${cpuData['percent'].toFixed(1)}%`, [
{name: 'used', value: cpuData['percent']},
{name: 'free', value: 100 - cpuData['percent']}
{ name: 'used', value: cpuData['percent'] },
{ name: 'free', value: 100 - cpuData['percent'] }
]))
memChart.setOption(createPieChartOption(`${localData['memory']}\n${memData['percent'].toFixed(1)}%`, [
{name: 'process', value: memData['usedProcess']},
{name: 'used', value: memData['used'] - memData['usedProcess']},
{name: 'free', value: memData['free']}
{ name: 'process', value: memData['usedProcess'] },
{ name: 'used', value: memData['used'] - memData['usedProcess'] },
{ name: 'free', value: memData['free'] }
]))
swapChart.setOption(createPieChartOption(`${localData['swap']}\n${swapData['percent'].toFixed(1)}%`, [
{name: 'used', value: swapData['used']},
{name: 'free', value: swapData['free']}
{ name: 'used', value: swapData['used'] },
{ name: 'free', value: swapData['free'] }
]))
@ -284,12 +285,12 @@ function main() {
document.getElementById('disk-info').appendChild(createBarChart(diskTitle, disk['percent']))
})
// 随机一言
let motto = mottos[Math.floor(Math.random() * mottos.length)]
let mottoText = motto['text']
let mottoFrom = `${motto['author']} ${motto['source']}`
let mottoText = motto_['text']
let mottoFrom = motto_['source']
document.getElementById('motto-text').innerText = mottoText
document.getElementById('motto-from').innerText = mottoFrom
// 致谢
document.getElementById('addition-info').innerText = '感谢 锅炉 云裳工作室 提供服务器支持'
}

View File

@ -103,7 +103,7 @@
)
// 从/js/motto.js中读取mottos{},随机选择一句
let motto = mottos[Math.floor(Math.random() * mottos.length)];
// let motto = mottos[Math.floor(Math.random() * mottos.length)];
// 正文在中间,作者和来源格式为--作者 来源,在右下方
let mottoDiv = document.getElementById('motto-info');
let mottoText = document.createElement('div');
@ -113,13 +113,13 @@
let mottoAuthor = document.createElement('div');
mottoAuthor.className = 'motto-author';
// motto.author和motto.source可能不存在为空所以要判断
if (!motto.author) {
motto.author = '';
}
// if (!motto.author) {
// motto.author = '';
// }
if (!motto.source) {
motto.source = '';
}
mottoAuthor.innerText = `\n--${motto.author} ${motto.source}`;
mottoAuthor.innerText = `\n${motto.source}`;
mottoAuthor.style.textAlign = 'right';
mottoDiv.appendChild(mottoAuthor);

View File

@ -10,31 +10,33 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
</div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
<div class="info-box" id="disks-info">
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
<div class="info-box" id="motto-info">
</div>
</div>
<div class="info-box" id="disks-info">
</div>
<div class="info-box" id="motto-info">
</div>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/bg.js"></script>
<script src="js/motto.js"></script>
<script src="js/style.js"></script>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/bg.js"></script>
<!-- <script src="js/motto.js"></script> -->
<script src="js/style.js"></script>
</body>
</html>
</html>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Liteyuki Status</title>
@ -8,43 +9,46 @@
<link rel="stylesheet" href="./css/fonts.css">
</head>
<body>
<template id="bot-template">
<div class="info-box bot-info">
<div class="bot-icon">
<img class="bot-icon-img" src="" alt="bot-icon">
</div>
<div class="bot-detail">
<div class="bot-name">
Liteyuki
<template id="bot-template">
<div class="info-box bot-info">
<div class="bot-icon">
<img class="bot-icon-img" src="" alt="bot-icon">
</div>
<hr>
<div class="bot-tags">
<!-- tag span-->
<div class="bot-detail">
<div class="bot-name">
TriM-Liteyuki
</div>
<hr>
<div class="bot-tags">
<!-- tag span-->
</div>
</div>
</div>
</div>
</template>
</template>
<template id="device-info">
<div class="device-info">
<div class="device-chart">
<template id="device-info">
<div class="device-info">
<div class="device-chart">
</div>
<div class="device-tags">
</div>
</div>
<div class="device-tags">
</div>
</div>
</template>
</template>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="hardware-info"></div>
<div class="info-box" id="disk-info"></div>
<div class="info-box" id="motto-info">
<div id="motto-text"></div>
<div id="motto-from"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<script src="./js/motto.js"></script>
<script src="./js/card.js"></script>
<script src="./js/status.js"></script>
<div class="data-storage" id="data">{{ data | tojson }}</div>
<div class="info-box" id="hardware-info"></div>
<div class="info-box" id="disk-info"></div>
<div class="info-box" id="motto-info">
<div id="motto-text"></div>
<div id="motto-from"></div>
</div>
<div class="info-box" id="addition-info"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
<!-- <script src="./js/motto.js"></script> -->
<script src="./js/card.js"></script>
<script src="./js/status.js"></script>
</body>
</html>

View File

@ -49,7 +49,8 @@
background-color: white;
}
.bot-name, .bot-tag {
.bot-name,
.bot-tag {
margin-left: 20px;
}
@ -93,35 +94,36 @@
font-style: italic;
color: #ccc;
}
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.3.0/dist/echarts.min.js"></script>
</head>
<body>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
<div class="info-box" id="hardware-info">
<div class="pie-info" id="cpu-info">
<div class="pie-chart" id="cpu-chart"></div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
</div>
</div>
<div class="pie-info" id="mem-info">
<div class="pie-chart" id="mem-chart"></div>
<div class="info-box" id="disks-info">
</div>
<div class="pie-info" id="swap-info">
<div class="pie-chart" id="swap-chart"></div>
<div class="info-box" id="motto-info">
</div>
</div>
<div class="info-box" id="disks-info">
</div>
<div class="info-box" id="motto-info">
</div>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<script src="js/motto.js"></script>
<script src="js/style.js"></script>
<!--储存数据div不显示-->
<div id="data" style="display: none">{{ data | tojson }}</div>
<!-- <script src="js/motto.js"></script> -->
<script src="js/style.js"></script>
</body>
</html>
</html>

View File

@ -1,23 +1,143 @@
import os.path
import time
# import time
from os import getcwd
import aiofiles
import nonebot
from nonebot_plugin_htmlrender import *
from .tools import random_hex_string
# import imgkit
# from typing import Any, Dict, Literal, Optional, Union
# import uuid
# import jinja2
# from pathlib import Path
# TEMPLATES_PATH = str(Path(__file__).parent / "templates")
# env = jinja2.Environment( # noqa: S701
# extensions=["jinja2.ext.loopcontrols"],
# loader=jinja2.FileSystemLoader(TEMPLATES_PATH),
# enable_async=True,
# )
# async def template_to_html(
# template_path: str,
# template_name: str,
# **kwargs,
# ) -> str:
# """使用jinja2模板引擎通过html生成图片
# Args:
# template_path (str): 模板路径
# template_name (str): 模板名
# **kwargs: 模板内容
# Returns:
# str: html
# """
# template_env = jinja2.Environment( # noqa: S701
# loader=jinja2.FileSystemLoader(template_path),
# enable_async=True,
# )
# template = template_env.get_template(template_name)
# return await template.render_async(**kwargs)
# async def template_to_pic(
# template_path: str,
# template_name: str,
# templates: Dict[Any, Any],
# pages: Optional[Dict[Any, Any]] = None,
# wait: int = 0,
# type: Literal["jpeg", "png"] = "png", # noqa: A002
# quality: Union[int, None] = None,
# device_scale_factor: float = 2,
# ) -> bytes:
# """使用jinja2模板引擎通过html生成图片
# Args:
# template_path (str): 模板路径
# template_name (str): 模板名
# templates (Dict[Any, Any]): 模板内参数 如: {"name": "abc"}
# pages (Optional[Dict[Any, Any]]): 网页参数 Defaults to
# {"base_url": f"file://{getcwd()}", "viewport": {"width": 500, "height": 10}}
# wait (int, optional): 网页载入等待时间. Defaults to 0.
# type (Literal["jpeg", "png"]): 图片类型, 默认 png
# quality (int, optional): 图片质量 0-100 当为`png`时无效
# device_scale_factor: 缩放比例,类型为float,值越大越清晰(真正想让图片清晰更优先请调整此选项)
# Returns:
# bytes: 图片 可直接发送
# """
# if pages is None:
# pages = {
# "viewport": {"width": 500, "height": 10},
# "base_url": f"file://{getcwd()}", # noqa: PTH109
# }
# template_env = jinja2.Environment( # noqa: S701
# loader=jinja2.FileSystemLoader(template_path),
# enable_async=True,
# )
# template = template_env.get_template(template_name)
# open(
# filename := os.path.join(
# template_path,
# str(uuid.uuid4())+".html",
# ),
# "w",
# ).write(await template.render_async(**templates))
# print(pages,filename)
# img = imgkit.from_file(
# filename,
# output_path=False,
# options={
# "format": type,
# "quality": quality if (quality and type == "jpeg") else 94,
# "allow": pages["base_url"],
# # "viewport-size": "{} {}".format(pages["viewport"]["width"],pages["viewport"]["height"]),
# "zoom": device_scale_factor,
# # "load-error-handling": "ignore",
# "enable-local-file-access": None,
# "no-stop-slow-scripts": None,
# "transparent": None,
# },
# ) # type: ignore
# # os.remove(filename)
# return img
# return await html_to_pic(
# template_path=f"file://{template_path}",
# html=await template.render_async(**templates),
# wait=wait,
# type=type,
# quality=quality,
# device_scale_factor=device_scale_factor,
# **pages,
# )
async def html2image(
html: str,
wait: int = 0,
html: str,
wait: int = 0,
):
pass
async def template2html(
template: str,
templates: dict,
template: str,
templates: dict,
) -> str:
"""
Args:
@ -32,12 +152,12 @@ async def template2html(
async def template2image(
template: str,
templates: dict,
pages=None,
wait: int = 0,
scale_factor: float = 1,
debug: bool = False,
template: str,
templates: dict,
pages=None,
wait: int = 0,
scale_factor: float = 1,
debug: bool = False,
) -> bytes:
"""
template -> html -> image
@ -53,11 +173,8 @@ async def template2image(
"""
if pages is None:
pages = {
"viewport": {
"width" : 1080,
"height": 10
},
"base_url": f"file://{getcwd()}",
"viewport": {"width": 1080, "height": 10},
"base_url": f"file://{getcwd()}",
}
template_path = os.path.dirname(template)
template_name = os.path.basename(template)
@ -70,7 +187,9 @@ async def template2image(
**templates,
)
random_file_name = f"debug-{random_hex_string(6)}.html"
async with aiofiles.open(os.path.join(template_path, random_file_name), "w", encoding="utf-8") as f:
async with aiofiles.open(
os.path.join(template_path, random_file_name), "w", encoding="utf-8"
) as f:
await f.write(raw_html)
nonebot.logger.info("Debug HTML: %s" % f"{random_file_name}")
@ -84,30 +203,30 @@ async def template2image(
)
async def url2image(
url: str,
wait: int = 0,
scale_factor: float = 1,
type: str = "png",
quality: int = 100,
**kwargs
) -> bytes:
"""
Args:
quality:
type:
url: str: URL
wait: int: 等待时间
scale_factor: float: 缩放因子
**kwargs: page 参数
Returns:
图片二进制数据
"""
async with get_new_page(scale_factor) as page:
await page.goto(url)
await page.wait_for_timeout(wait)
return await page.screenshot(
full_page=True,
type=type,
quality=quality
)
# async def url2image(
# url: str,
# wait: int = 0,
# scale_factor: float = 1,
# type: str = "png",
# quality: int = 100,
# **kwargs
# ) -> bytes:
# """
# Args:
# quality:
# type:
# url: str: URL
# wait: int: 等待时间
# scale_factor: float: 缩放因子
# **kwargs: page 参数
# Returns:
# 图片二进制数据
# """
# async with get_new_page(scale_factor) as page:
# await page.goto(url)
# await page.wait_for_timeout(wait)
# return await page.screenshot(
# full_page=True,
# type=type,
# quality=quality
# )

View File

@ -75,8 +75,8 @@ class MarkdownMessage:
group_id = event.group_id if message_type == "group" else None
user_id = event.user.id if isinstance(event, satori.event.Event) else event.user_id
session_id = user_id if message_type == "private" else group_id
else:
pass
try:
raise TencentBannedMarkdownError("Tencent banned markdown")
forward_id = await bot.call_api(

View File

@ -1,18 +1,18 @@
from nonebot.plugin import PluginMetadata
from .monitors import *
from .matchers import *
__author__ = "snowykami"
__plugin_meta__ = PluginMetadata(
name="轻雪智障回复",
description="",
usage="",
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki": True,
"toggleable" : True,
"default_enable" : True,
}
from nonebot.plugin import PluginMetadata
from .monitors import *
from .matchers import *
__author__ = "snowykami"
__plugin_meta__ = PluginMetadata(
name="轻雪智障回复",
description="",
usage="",
type="application",
homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki": True,
"toggleable" : True,
"default_enable" : True,
}
)

View File

@ -1,106 +1,106 @@
import asyncio
import random
import nonebot
from nonebot import Bot, on_message, get_driver, require
from nonebot.internal.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from nonebot.typing import T_State
from src.utils.base.ly_typing import T_MessageEvent
from .utils import get_keywords
from src.utils.base.word_bank import get_reply
from src.utils.event import get_message_type
from src.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
from src.utils.base.data_manager import group_db, Group
require("nonebot_plugin_alconna")
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
nicknames = set()
driver = get_driver()
group_reply_probability: dict[str, float] = {
}
default_reply_probability = 0.05
cut_probability = 0.4 # 分几句话的概率
@on_alconna(
Alconna(
"set-reply-probability",
Args["probability", float, default_reply_probability],
),
aliases={"设置回复概率"},
permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER,
).handle()
async def _(result: Arparma, event: T_MessageEvent, matcher: Matcher):
# 修改内存和数据库的概率值
if get_message_type(event) == "group":
group_id = event.group_id
probability = result.main_args.get("probability")
# 保存到数据库
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=str(group_id)))
group.config["reply_probability"] = probability
group_db.save(group)
await matcher.send(f"已将群组{group_id}的回复概率设置为{probability}")
return
@group_db.on_save
def _(model: Group):
"""
在数据库更新时更新内存中的回复概率
Args:
model:
Returns:
"""
group_reply_probability[model.group_id] = model.config.get("reply_probability", default_reply_probability)
@driver.on_bot_connect
async def _(bot: Bot):
global nicknames
nicknames.update(bot.config.nickname)
# 从数据库加载群组的回复概率
groups = group_db.where_all(Group(), default=[])
for group in groups:
group_reply_probability[group.group_id] = group.config.get("reply_probability", default_reply_probability)
@on_message(priority=100).handle()
async def _(event: T_MessageEvent, bot: Bot, state: T_State, matcher: Matcher):
kws = await get_keywords(event.message.extract_plain_text())
tome = False
if await to_me()(event=event, bot=bot, state=state):
tome = True
else:
for kw in kws:
if kw in nicknames:
tome = True
break
# 回复概率
message_type = get_message_type(event)
if tome or message_type == "private":
p = 1.0
else:
p = group_reply_probability.get(event.group_id, default_reply_probability)
if random.random() < p:
if reply := get_reply(kws):
if random.random() < cut_probability:
reply = reply.replace("", "||").replace("", "||").replace("", "||").replace("", "||")
replies = reply.split("||")
for r in replies:
if r: # 防止空字符串
await asyncio.sleep(random.random() * 2)
await matcher.send(r)
else:
await asyncio.sleep(random.random() * 3)
await matcher.send(reply)
return
import asyncio
import random
import nonebot
from nonebot import Bot, on_message, get_driver, require
from nonebot.internal.matcher import Matcher
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from nonebot.typing import T_State
from src.utils.base.ly_typing import T_MessageEvent
from .utils import get_keywords
from src.utils.base.word_bank import get_reply
from src.utils.event import get_message_type
from src.utils.base.permission import GROUP_ADMIN, GROUP_OWNER
from src.utils.base.data_manager import group_db, Group
require("nonebot_plugin_alconna")
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma
nicknames = set()
driver = get_driver()
group_reply_probability: dict[str, float] = {
}
default_reply_probability = 0.05
cut_probability = 0.4 # 分几句话的概率
@on_alconna(
Alconna(
"set-reply-probability",
Args["probability", float, default_reply_probability],
),
aliases={"设置回复概率"},
permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER,
).handle()
async def _(result: Arparma, event: T_MessageEvent, matcher: Matcher):
# 修改内存和数据库的概率值
if get_message_type(event) == "group":
group_id = event.group_id
probability = result.main_args.get("probability")
# 保存到数据库
group: Group = group_db.where_one(Group(), "group_id = ?", group_id, default=Group(group_id=str(group_id)))
group.config["reply_probability"] = probability
group_db.save(group)
await matcher.send(f"已将群组{group_id}的回复概率设置为{probability}")
return
@group_db.on_save
def _(model: Group):
"""
在数据库更新时更新内存中的回复概率
Args:
model:
Returns:
"""
group_reply_probability[model.group_id] = model.config.get("reply_probability", default_reply_probability)
@driver.on_bot_connect
async def _(bot: Bot):
global nicknames
nicknames.update(bot.config.nickname)
# 从数据库加载群组的回复概率
groups = group_db.where_all(Group(), default=[])
for group in groups:
group_reply_probability[group.group_id] = group.config.get("reply_probability", default_reply_probability)
@on_message(priority=100).handle()
async def _(event: T_MessageEvent, bot: Bot, state: T_State, matcher: Matcher):
kws = await get_keywords(event.message.extract_plain_text())
tome = False
if await to_me()(event=event, bot=bot, state=state):
tome = True
else:
for kw in kws:
if kw in nicknames:
tome = True
break
# 回复概率
message_type = get_message_type(event)
if tome or message_type == "private":
p = 1.0
else:
p = group_reply_probability.get(event.group_id, default_reply_probability)
if random.random() < p:
if reply := get_reply(kws):
if random.random() < cut_probability:
reply = reply.replace("", "||").replace("", "||").replace("", "||").replace("", "||")
replies = reply.split("||")
for r in replies:
if r: # 防止空字符串
await asyncio.sleep(random.random() * 2)
await matcher.send(r)
else:
await asyncio.sleep(random.random() * 3)
await matcher.send(reply)
return

View File

@ -1,13 +1,13 @@
from jieba import lcut
from nonebot.utils import run_sync
@run_sync
def get_keywords(text: str) -> list[str, ...]:
"""
获取关键词
Args:
text: 文本
Returns:
"""
return lcut(text)
from jieba import lcut
from nonebot.utils import run_sync
@run_sync
def get_keywords(text: str) -> list[str, ...]:
"""
获取关键词
Args:
text: 文本
Returns:
"""
return lcut(text)